回复“ 000 ”获取大量电子书
建议先看前面并发编程系列的文章:
快速掌握并发编程---synchronized篇(上)
快速掌握并发编程---synchronized篇(下)
synchronized 结合 java.lang.Object
对象中的wait()
、notify()
、notifyAll()
。
应用 线程A
public class ThreadA extends Thread { private Object lock; public ThreadA (Object lock) { this .lock = lock; } @Override public void run () { synchronized (lock){ System.out.println("ThreadA---start" ); try { //实现线程阻塞 lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ThreadA---end" ); } } }
线程B
public class ThreadB extends Thread { private Object lock; public ThreadB (Object lock) { this .lock = lock; } @Override public void run () { synchronized (lock) { System.out.println("ThreadB---start" ); //实现线程的唤醒 lock.notify(); System.out.println("ThreadB---end" ); } } }
测试
public class WaitDemo { public static void main (String[] args) { Object lock = new Object(); ThreadA threadA = new ThreadA(lock); threadA.start(); ThreadB threadB = new ThreadB(lock); threadB.start(); } }
运行输出
ThreadA---start ThreadB---start ThreadB---end ThreadA---end
ThreadA阻塞挂起,ThreadB唤醒,ThreadA被唤醒。
上面这段代码我们会发现被阻塞的线程什么时候被唤醒,取决于获得锁的线程什么时候执行完同步代码块并且释放锁。
那怎么做到显示控制呢?我们就需要借 助 一 个 信 号机 制 :在 Object 对 象 中 ,提 供 了wait/notify/notifyall,可以用于控制线程的状态
wait/notify/notifyAll 基本概念 wait:表示持有对象锁的线程 A 准备释放对象锁权限,释放 CPU
资源并进入等待状态。
notify:表示持有对象锁的线程 A 准备释放对象锁权限,通知 JVM
唤醒某个竞争该对象锁的线程 X。线程 A 同步代码块执行结束并且释放了锁之后,线程 X 直接获得对象锁权限,其他竞争线程继续等待(即使线程 X 同步完毕,释放对象锁,其他竞争线程仍然等待,直至有新的 notify ,notifyAll 被调用)。
notifyAll:notifyall 和 notify 的区别在于,notifyAll 会唤醒所有竞争同一个对象锁的所有线程,当已经获得锁的线程A 释放锁之后,所有被唤醒的线程都有可能获得对象锁权限(notifyAll唤醒等待队列中所有线程,然后所有被唤醒的线程重新进入锁竞争)。
需要注意的是:
三个方法都必须在 synchronized 同步关键字所限定的作用域中调用 ,否则会报错
java.lang.IllegalMonitorStateException
意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。另外,通过同步机制来确保线程从 wait 方法返回时能够感知到感知到 notify 线程对变量做出的修改waity /notify 。
waity /notify 的基本原理
注意两个队列:
sleep与wait的区别 sleep
wait 让当前线程进入等待状态,当别的其他线程调用notify()或者notifyAll()方法时,当前线程进入就绪状态
wait方法必须在同步上下文中调用,例如:同步方法块或者同步方法中,这也就意味着如果你想要调用wait方法,前提是必须获取对象上的锁资源
当wait方法调用时,当前线程将会释放已获取的对象锁资源,并进入等待队列,其他线程就可以尝试获取对象上的锁资源。
wait是Object中的方法