wait/notify详解(二)

一:wait/notify详解

1.1:wait方法,立即释放锁
public class Demo {

    private static Object lock = new Object();

    public static void main(String[] args) {

        new Thread(() -> {
            try {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+" :wait start");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName()+" :wait end");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"高铁").start();

        new Thread(() -> {
            try {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+" :wait start");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName()+" :wait end");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"飞机").start();
    }
}
  • 控制台
高铁 :wait start
飞机 :wait start
注: 程序还没停止!
分析:
假设wait()方法不释放锁,那么当高铁线程进入后,wait()住了,那么飞机线程是不可能进去的,因为是同一把锁
而由控制台可以看出,就算是同一把锁,飞机线程也还是进去了,所以结论是wait()方法会立即释放锁!
1.2:sleep方法, 在指定的时间内不释放锁

注: 还是上面的例子,只不过将wait()改成sleep()进行演示

public class Demo {

    private static Object lock = new Object();

    public static void main(String[] args) {

        new Thread(() -> {
            try {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+" :sleep start");
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName()+" :sleep end");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"高铁").start();

        new Thread(() -> {
            try {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+" :sleep start");
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName()+" :sleep end");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"飞机").start();
    }
}

高铁 :sleep start ①
高铁 :sleep end ②
飞机 :sleep start ③
飞机 :sleep end   ④
注:程序已经停止
分析:
由控制台可以看出,高铁线程执行完①后,一直等了5秒后,才去执行②,说明5秒期间高铁线程并没有去释放锁
三:wait(long timeout)

被其他线程对锁进行notify()通知唤醒或者时间到自动唤醒后,如果想向下运行,则需要重新持有锁!
如果没有锁,则一直等待,直到持有锁为止!
大白话:就是你被唤醒了,并不说明你可以马上往下运行,还是得去抢锁!抢到了才能往下运行!

1、业务类

public class MyService {

    public void methodA(){
       try {
           synchronized (this){
               System.out.println("wait begin: "+Thread.currentThread().getName()+" ,timer: "+System.currentTimeMillis());
               this.wait(3000);
               System.out.println("wait end: "+Thread.currentThread().getName()+" ,timer: "+System.currentTimeMillis());
           }
       }catch (InterruptedException e){
           e.printStackTrace();
       }
    }

    //同步方法的锁对象是this
    public synchronized void methodB(){
        try {
            Thread.sleep(6000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    
}

注:两个方法使用的是同一把锁!

2、线程类(两个)

ThreadA线程:执行业务类中的methodA方法

public class ThreadA extends Thread{

    private MyService myService;

    public ThreadA(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodA();
    }
}

ThreadB线程:执行业务类中的methodB方法

public class ThreadB extends Thread{

    private MyService myService;

    public ThreadB(MyService myService){
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.methodB();
    }
}

3、测试类

public class Demo {
    public static void main(String[] args) {
        MyService myService = new MyService();

        ThreadA[] myThreadAS = new ThreadA[10];
        //0~1, 赋值并启动
        IntStream.range(0,2).forEach(i -> {
            myThreadAS[i] = new ThreadA(myService);
            myThreadAS[i].start();
        });

        ThreadB threadB = new ThreadB(myService);
        threadB.start();
    }
}

4、控制台

wait begin: Thread-0 ,timer: 1596546932903
wait begin: Thread-1 ,timer: 1596546932903
wait end: Thread-1 ,timer: 1596546938917
wait end: Thread-0 ,timer: 1596546938917

5、分析

wait begin: Thread-0 ,timer: 1596546932903
wait begin: Thread-1 ,timer: 1596546932903
1.时间一模一样:第一个A线程先拿到锁,然后输出wait begin,执行完wait(3000)方法后,进入TIMED_WAITING状态,并释放锁,第二个A线程拿到锁之后步骤和上面一样,由控制台可以看出,上面执行完后甚至1毫秒都没花费掉,可见速度多快!!
2.B线程同时也启动了,但由于之前没抢到锁,所以没执行run中的任务,因为A线程和B线程抢的是同一把锁,
此时两个A线程都进入了TIMED_WAITING状态,那么B线程此时就可以轻而易举的抢到了锁,然后执行里面的Thread.sleep(6000),但该方法在指定的时间内并不会去释放锁,在线程B方法中等待3秒的同时,线程A中的wait(3000)也自动被唤醒了,但由于线程B中的sleep方法并不释放锁,而线程A就算被唤醒了,也不能立马往下执行,还是需要抢到锁往下执行,所以只能乖乖的等到线程B休眠6秒后,此时线程A才拿到锁,输出下面的wait end语句.

来自:虽然帅,但是菜的cxy

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值