线程通信
除了使用synchronized来对代码块和方法进行同步外,jdk1.5之后还有一种Lock同步锁的方式进行同步
使用lock.lock()来进行加锁,使用lock.unlock()方法来释放锁
既然可以使用lock来代替synchronized,那么如何进行实现synchronized与wait()、notify()、notifyAll()的线程通信机制呢
在使用lock时使用Condition来进行线程通信
下面来使用两种方式来分别展示一下线程间通信
使用Object的wait()、notify进行线程通信
阻塞
调用wait()方法,将阻塞挂起等待其他线程的通知,进入该对象的线程等待池中,调用wait()方法之前,线程必须要获得该对象的对象级别锁,即只能在同步块或者同步方法中使用,否则会报IllegalMonitorStateException异常
唤醒
调用notify()方法和notifyAll()方法来通知那些等待该对象锁的其他线程,(如果有多个线程等待,notify会任意挑选一个线程来进行通知,notifyAll会对所有该对象上由于调用wait方法而被挂起的线程进行通知),唤醒之后的线程会进入该对象的锁池中,需要竞争到对象的监视器锁才可以继续执行,调用notify()方法和notifyAll()方法之前,线程必须要获得该对象的对象级别锁,即只能在同步块或者同步方法中使用
除了调用notify()方法和notifyAll()方法来唤醒线程之外,还可以使用中断的方式来使得线程在wait()处抛出InterruptedException异常而返回并终止
如果使用的是wait(timeout)方法进行阻塞的,那么也会由于在指定时间内没有被唤醒而因为超时返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
public class TestThreadSignal { public static void main(String[] args) { PrintRunnable runnable = new PrintRunnable(); new Thread(runnable,"线程一").start(); new Thread(runnable,"线程二").start(); } }
class PrintRunnable implements Runnable{ int num = 1; @Override public void run() { while (true){ synchronized (this){ notify(); if(num <= 100){ System.out.println(Thread.currentThread().getName() + "打印" + num++); } else { break; } try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
} } }
|
虚假唤醒现象
有时在没有被其他线程调用notify/notifyAll,或者没有被中断,或者没有等待超时,也有可能会从挂起状态变为运行状态(虚假唤醒),虽然概率很低,但是最好还是使用while(条件)来一直查看条件是否满足
1 2 3 4 5
| synchronized(obj){ while(条件){ obj.wait(); } }
|
使用condition的await()、signal()进行线程通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
public class TestThreadSignalForLock { public static void main(String[] args) { PrintRunnableForLock runnable = new PrintRunnableForLock(); new Thread(runnable,"线程一").start(); new Thread(runnable,"线程二").start(); } }
class PrintRunnableForLock implements Runnable{ int num = 1; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); @Override public void run() { while (true){ try{ lock.lock(); condition.signal(); if(num <= 100){ System.out.println(Thread.currentThread().getName() + "打印" + num++); } else { break; } try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } finally { lock.unlock(); }
} } }
|