多线程基础知识第二篇:线程同步和线程通信
首先区分一下概念,什么是线程同步,什么是线程通信。
线程同步是指
同步监视器(同步代码块、同步方法) synchronized
锁 Lock
线程通信
线程通信有两种机制,一是用监视器锁的wait/notify机制,二是用Condition的await/signal机制。
wait/notify是配合监视器锁使用的,await/signal是配合Lock使用的。
wait/notify机制又称为等待/通知机制,指的是,在线程A中调用了锁对象的wait()方法后,线程A立即释放锁并进入监视器锁对象的等待队列(变为waiting状态),在另一个线程B调用了监视器锁对象的notify()或者notifyAll()方法,线程A收到通知,待线程B释放监视器锁后,再去竞争监视器锁,如果获取到监视器锁,则从wait()方法返回,执行后续操作。
wait()方法调用线程必须先获取到这个监视器锁之后才能调用wait()方法,否则会抛IllegalMonitorStateException异常。调用wait()方法后,调用线程释放掉监视器锁,并且等待,直到另一个线程中调用了同一个监视器锁对象的notify()方法或者notifyAll()方法。
notify()方法调用线程也必须先获得获取到这个监视器锁,否则也会抛IllegalMonitorStateException异常。notify()方法会唤醒在这个监视器锁上等待的某一个线程,被唤醒的线程会在调用notify()方法的线程释放监视器锁之后,和其他线程一样去竞争监视器锁,获取到监视器锁的机会和其他线程是均等的。notifyAll()方法会唤醒在这个监视器锁上等待的所有线程。注意,notify()/notifyAll()方法不会释放监视器锁,等同步代码块或者同步方法执行完,才会释放监视器锁。
释放监视器锁的时机有:
1、线程执行完
2、线程抛异常
3、线程调用监视器锁的wait()方法
Condition的await/signal机制,主要用到Condition接口中的方法
await:
void await() throws InterruptedException:
调用者Condition实例对应的锁会被释放,调用者线程会等待,直到以下情况发生:
1、在其他线程中调用了同一个Condition实例的signal()方法,且上述await线程刚好被选中通知唤醒
2、在其他线程中调用了同一个Condition实例的signalAll()方法
3、在其他线程中调用await线程的interrupt()实例方法中断了该线程
In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.
在await()方法返回之前,await线程必须要重新获取到对应的锁。换句话说,返回的话一定已经获取到了锁。完成业务后,不要忘了调用锁实例的unlock方法释放掉锁。
signal:
signal():唤醒一个在这个Condition实例上等待的线程。
signalAll():唤醒在这个Condition实例上等待的全部线程。
Condition实例的await和signal方法,都必须在调用线程获得了该Condition实例对应的锁之后再调用,否则也会抛IlleagleMonitorStateException。
Condition实例不是new出来的,而是通过调用Lock实例的newCondition()方法获得的。Lock接口的实现类有ReentrantLock、ReentrantReadWriteLock.WriteLock、ReentrantReadWriteLock.ReadLock。而可重入读写锁的读锁不支持Condition,仅写锁支持Condition。