- 介绍
- Java中线程协作的最常见的两种方式:利用Object.wait()、Object.notify()和使用Condition
- 方法一
- Object中的wait、notify、notifyAll方法定义如下
- public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException;
- wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写
- 调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
- 调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程
- 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程
- 之所以这三个方法声明在Object类中是因为每个对象都拥有monitor(即锁)
- 调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行
- 示例
-
public class Test { public static Object object = new Object(); public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } thread2.start(); } static class Thread1 extends Thread{ @Override public void run() { synchronized (object) { try { object.wait(); } catch (InterruptedException e) { } System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁"); } } } static class Thread2 extends Thread{ @Override public void run() { synchronized (object) { object.notify(); System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()"); } System.out.println("线程"+Thread.currentThread().getName()+"释放了锁"); } } }
- 运行结果
- 线程Thread-1调用了object.notify()
线程Thread-1释放了锁
线程Thread-0获取到了锁
- 线程Thread-1调用了object.notify()
-
- 方法二
- Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效
- Condition是个接口,基本的方法就是await()和signal()方法
- Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
- 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
- 示例
-
public class Test { private int queueSize = 10; private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize); private Lock lock = new ReentrantLock(); private Condition notFull = lock.newCondition(); private Condition notEmpty = lock.newCondition(); public static void main(String[] args) { Test test = new Test(); Producer producer = test.new Producer(); Consumer consumer = test.new Consumer(); producer.start(); consumer.start(); } class Consumer extends Thread{ @Override public void run() { consume(); } private void consume() { while(true){ lock.lock(); try { while(queue.size() == 0){ try { System.out.println("队列空,等待数据"); notEmpty.await(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.poll(); //每次移走队首元素 notFull.signal(); System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素"); } finally{ lock.unlock(); } } } } class Producer extends Thread{ @Override public void run() { produce(); } private void produce() { while(true){ lock.lock(); try { while(queue.size() == queueSize){ try { System.out.println("队列满,等待有空余空间"); notFull.await(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.offer(1); //每次插入一个元素 notEmpty.signal(); System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size())); } finally{ lock.unlock(); } } } } }