多线程6(接5)

内存可见性

在“多线程5”末尾提到线程安全我呢提,原因在于每个线程都有一个自己的内存,同时他们又共享一个主内存,当线程要循环读取主内存的变量的时候,线程就会把主内存的变量拷贝到自己的线程内存里面读取,所以后续对主内存进行修改,线程仍然在自己的线程内存里面读取之前拷贝过来的变量,感知不到主内存的变化

wait和notify

可以让后执行的逻辑等待先执行的逻辑先跑完,再开始运行。

join和wait的区别

join是要让先运行的线程全部运行完毕,再开始执行下一个。

wait是让前一个线程执行完一段代码(无需全部运行完毕),就可以开始执行。

wait可以控制逻辑运行的顺序,可以很好的协调线程的执行顺序,拿到锁的线程运行到一半,如果来到了没到执行该逻辑的时机,就用wait阻塞等待。

wait可以释放锁,但是要释放锁的前提是加锁,所有在用wait的对象一定要处于加锁状态。

public class xxx{
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        System.out.println("whit前");
        synchronized(object){
            object.wait();
        }
        System.out.println("wait后");  
    }
}

其他线程完成工作后,调用notify唤醒这个wait线程,wait就会解除阻塞,重新获取到锁继续执行。

public class Demo24 {
    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();
        Thread t1 = new Thread(()->{
            try{
                System.out.println("whit前");
                synchronized (locker) {
                    locker.wait();
                }
                System.out.println("whit后");
            }catch (InterruptedException e){
                throw new RuntimeException();
            }
        });
        Thread t2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            System.out.println("输入任意内容唤醒t1");
            scanner.next();
            synchronized(locker){
                locker.notify();
            }

        });
    }
}

notify也强制要求和synchronized使用,并且涉及到锁的对象必须是相同的,并且必须要wait线程先运行notify再运行。

notify一次只能唤醒有个wait线程,是随机的,不确定每次唤醒的线程是哪个。

public class xxx {
        public static void main(String[] args) throws InterruptedException {
            Object locker = new Object();
            Thread t1 = new Thread(()->{
                try{
                    System.out.println("t1whit前");
                    synchronized (locker) {
                        locker.wait();
                    }
                    System.out.println("t1whit后");
                }catch (InterruptedException e){
                    throw new RuntimeException();
                }
            });
            Thread t2 = new Thread(()->{
                try{
                    System.out.println("t2whit前");
                    synchronized (locker) {
                        locker.wait();
                    }
                    System.out.println("t2whit后");
                }catch (InterruptedException e){
                    throw new RuntimeException();
                }
            });
            Thread t3 = new Thread(()->{
                Scanner scanner = new Scanner(System.in);
                System.out.println("输入任意内容唤醒");
                scanner.next();
                synchronized(locker){
                    locker.notify();
                }
            });
            t1.start();
            t2.start();
            t3.start();
        }
    }

上面代码在唤醒线程的时候是随机唤醒t1或者t2,如果想要两个同时唤醒则要在t3线程里再加入一个notify线程。但这种方法有些麻烦,在这我们还有一个可以一键唤醒的方法notifyAll。

虽然notifyAll可以一键唤醒所有的wait,但是要注意的是wait是停止阻塞回到重新加锁执行状态,实际上他们还是一个一个的执行。

wait和sleep的区别

wait和sleep很像,但最主要的区别在于z针对锁的操作,wait需要加锁才能使用,而sleep不需要。

如果再synchronized内使用,sleep不会释放掉锁,而wait会释放出锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值