详述线程间协作

例如:

上部分进程负责显示时间,下部分线程负责获取时间

synchronized关键字只是起到了多个线程“串行”执行临界区中代码的作用,但是哪个线程先执行,哪个线程后执行依无法确定,Object类中的wait()、notify()和notifyAll()三个方法解决了线程间的协作问题,通过这三个方法的“合理”使用可以确定多线程中线程的先后执行顺序:
1、wait():对象锁调用了wait()方法会使当前持有该对象锁的线程处于线程等待状态同时该线程释放对对象锁的控制权,直到在其他线程中该对象锁调用notify()方法或notifyAll()方法时等待此对象锁的线程才会被唤醒。
2、notify():对象锁调用notify()方法就会唤醒在此对象锁上等待的单个线程
3、notifyAll():对象锁调用notifyAll()方法就会唤醒在此对象锁上等待的所有线程;调用notifyAll()方法并不会立即激活某个等待线程,它只能撤销等待线程的中断状态,这样它们就能够在当前线程退出同步方法或同步代码块法后与其它线程展开竞争,以争取获得资源对象来执行。
一句话:谁调用了wait方法,谁就必须调用notify或notifyAll方法,并且“谁”是对象锁

使用Object类中的wait()、notify()和notifyAll()三个方法需要注意以下几点:
1、wait()方法需要和notify()或notifyAll()方法中的一个配对使用,且wait方法与notify()或notifyAll()方法配对使用时不能在同一个线程中(参见代码1)。
2、wait()方法、notify()方法和notifyAll()方法必须在同步方法或者同步代码块中使用否则出现IllegalMonitorStateException 异常
3、调用wait()方法、notify()方法和notifyAll()方法的对象必须和同步锁对象是一个对象。(参见代码2)

sleep()方法和wait()方法区别

sleep()方法被调用后当前线程进入阻塞状态,但是当前线程仍然持有对象锁,在当前线程sleep期间,其它线程无法执行sleep方法所在临界区中的代码。

对象锁调用了wait()方法会使当前持有该对象锁的线程处于线程等待状态同时该线程释放对对象锁的控制权,在当前线程处于线程等待期间,其它线程可以执行wait方法所在临界区中的代码。

wait()方法

尽管此处是死循环,但由于对象锁lockObj调用了wait()方法,使得分别持有该lockObj对象锁的“1号计数器”线程和“2号计数器”线程处于线程等待状态,所以循环并没有继续下去

为什么时间线程没有进入阻塞状态呢?——timeThread变量所代表的对象充当对象锁,由于该代码在main方法中,也就是说将来由主线程执行临界区中的代码,也就是说主线程是持有对象锁的线程,主线程执行完“timeThread.wait()”代码后进入阻塞状态,是主线程进入阻塞状态而非时间线程,这也是main方法中“System.out.println("main方法");”代码不执行的原因。

notify()方法

notifyAll()方法

尽管左图蓝框里是死循环, “1号计数器”线程和“2号计数器”线程输出1后对象锁lockObj调用了wait()方法,使得两个线程进入线程等待状态;但主线程在sleep 5000毫秒后启动了NotifyAllThread线程类创建的线程对象,该线程对象在执行run方法时对象锁调用了notifyAll方法,致使两个线程全部被唤醒,所以两个线程又循环了一遍

猜你喜欢

转载自blog.csdn.net/m0_46383618/article/details/113732094
今日推荐