一、等待与通知
public final void wait() throws InterruptedException
等待条件的发生。
public final void wait(long timeout) throws InterruptedException
等待条件的发生。如果通知没有在timeout指定的时间内发生,它还是会返回。
public final void wait(long timeout, int nanos) throws InterruptedException
等待条件的发生。如果通知没有在timeout指定的毫秒与纳秒内发生,它还是会返回。
public final void notify()
通知正在等待的Thread此条件已经发生。
public final void notifyAll()
通知所有正在等待的Thread此条件已经发生。
等待-通知机制的目的为何?它是如何运作的?
等待-通知机制是同步机制。它更是一个通信机制:它能够让某个Thread与其他Thread在特定条件符合时进行通信。等待-通知机制并没有指定特定条件是什么。
等待-通知机制能够用来取代synchronized机制吗?
不行,wait、notify、notifyAll方法方法必须从synchronized方法块中调用,因为需要其确保等待与通知的线程安全不会出现竞态条件。
public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable { private boolean done = true; private int curX = 0; private Thread timer = null; public AnimatedCharacterDisplayCanvas() { } public AnimatedCharacterDisplayCanvas(CharacterSource cs) { super(cs); } public synchronized void newCharacter(CharacterEvent ce) { curX = 0; tmpChar[0] = (char) ce.character; repaint(); } protected synchronized void paintComponent(Graphics gc) { Dimension d = getSize(); gc.clearRect(0, 0, d.width, d.height); if (tmpChar[0] == 0) return; int charWidth = fm.charWidth(tmpChar[0]); gc.drawChars(tmpChar, 0, 1, curX++, fontHeight); } public synchronized void run() { while (true) { try { if (done) { wait(); } else { repaint(); wait(100); } } catch (InterruptedException ie) { return; } } } public synchronized void setDone(boolean b) { done = b; if (timer == null) { timer = new Thread(this); timer.start(); } if (!done) notify(); } }
sleep与wait方法的区别?
wait与notify方法都必须在同步方法中,在一个类中的两个同步方法使用的都是当前this作为锁,wait方法执行后会释放掉当前方法锁,因为如果不释放的话notify永远无法获取到此锁,也就永远无法执行notify。
sleep方法是不会释放锁的,并且阻塞当前线程,一直到sleep指定的时间结束。
等待-通知机制与同步
存在于等待-通知机制中的竞态条件细节是什么?
1. 第一个Thread测试条件并确认它需要等待
2. 第二个Thread设定此条件
3. 第二个Thread调用notify方法,这不会被收到,因为第二个Thread还没有进入等待
4. 第一个Thread调用wait方法
这个潜在的竞态条件状况是如何解决的?
调用wait与调用notify的方法都使用同一锁(当前对象this),由锁来保证操作的原子性。
如果Thread收到通知,是否能够保证条件被正确的设定?
不是,描述情景
wait(), notify() 与 notifyAll()
当一个以上的Thread在等待通知时哪个Thread会在调用notify的时候收到通知?
Java规范没有定义哪一个Thread收到通知。但是Object class 提供另外一个方法notifyAll
是否noitfyAll方法真的唤醒所有的Thread?
是也不是。所有等待中Thread都会被唤醒,但它们都还没要重新取得对象的lock。所以这些Thread并不是并行地执行:它们都必须等待对象lock被释放掉。因此,一次只有一个Thread能够执行,且只有在调用notifyAll方法的这个Thread释放掉它的lock之后。
为什么要唤醒所有的Thread?
1. 有多个Thread处于等待状态,无法指定哪一个收到通知
2. 并不知道具体有多少个Thread处于等待,干脆同步通知,由等待中的Thread自己处理。
等待-通知机制与synchronized块
public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable { private boolean done = true; private int curX = 0; private Thread timer = null; private Object doneLock = new Object(); public AnimatedCharacterDisplayCanvas() { } public AnimatedCharacterDisplayCanvas(CharacterSource cs) { super(cs); } public synchronized void newCharacter(CharacterEvent ce) { curX = 0; tmpChar[0] = (char) ce.character; repaint(); } protected synchronized void paintComponent(Graphics gc) { Dimension d = getSize(); gc.clearRect(0, 0, d.width, d.height); if (tmpChar[0] == 0) return; int charWidth = fm.charWidth(tmpChar[0]); gc.drawChars(tmpChar, 0, 1, curX++, fontHeight); } public void run() { synchronized(doneLock) { while (true) { try { if (done) { doneLock.wait(); } else { repaint(); doneLock.wait(100); } } catch (InterruptedException ie) { return; } } } } public void setDone(boolean b) { synchronized(doneLock) { done = b; if (timer == null) { timer = new Thread(this); timer.start(); } if (!done) doneLock.notify(); } } }
二、条件变量
POSIX条件变量的四个基本函数:wait(), thimeed_wait(), signal, broadcast。直接对应Java提供的wait(), wait(long),notify(),notifyAll
J2SE 5.0加入提供条件变量功能的类。此类食欲Lock interface并用。因为这个新的interface是与调用以及lock对象分开的,它在使用方法上的灵活性就如筒其他Threading系统中的条件变量一样。
public class RandomCharacterGenerator extends Thread implements CharacterSource { private static char[] chars; private static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789"; static { chars = charArray.toCharArray(); } private Random random; private CharacterEventHandler handler; private boolean done = true; private Lock lock = new ReentrantLock(); private Condition cv = lock.newCondition(); public RandomCharacterGenerator() { random = new Random(); handler = new CharacterEventHandler(); } public int getPauseTime() { return (int) (Math.max(1000, 5000 * random.nextDouble())); } public void addCharacterListener(CharacterListener cl) { handler.addCharacterListener(cl); } public void removeCharacterListener(CharacterListener cl) { handler.removeCharacterListener(cl); } public void nextCharacter() { handler.fireNewCharacter(this, (int) chars[random.nextInt(chars.length)]); } public void run() { try { lock.lock(); while (true) { try { if (done) { cv.await(); } else { nextCharacter(); cv.await(getPauseTime(), TimeUnit.MILLISECONDS); } } catch (InterruptedException ie) { return; } } } finally { lock.unlock(); } } public void setDone(boolean b) { try { lock.lock(); done = b; if (!done) cv.signal(); } finally { lock.unlock(); } } }
为什么使用Condition而不使用wait与notify?或者说是二者的区别?
1. Condition与wait相同都是因为需要确保同步安全(即避免竞态条件)而必须使用锁机制保证。
2. Lock对象不能与wait、notify方法搭配,因为这些方法已经在内部被用来实现Lock对象,持有lock对象并不表示持有了该对象的同步锁。
3. Condition对象不像等待-通知机制,它是被创建不同的对象。对每一个Lock对象都可以创建一个以上的Condition对象,这表示我们可以针对个别的Thread或ThreadGroup进行独立的设定。
Condition方法:
void await()
等待条件的发生。
void awaitUniterruptibly()
等待条件的发生。与await()不同,它的调用不可能被中断。
void signal()
通知某个等待使用Condition对象的Thread此条件已经发生。
void signalAll()
通知所有等待使用Condition对象的Thread此条件已经发生。
Java 线程第三版 第四章 Thread Notification 读书笔记,布布扣,bubuko.com