在上篇我们看到,A线程往公共资源库(对象)提供了一条数据,然后B线程从库中提取了数据并打印出来。
实际项目中,我们不可能只往库中提供一条数据,而且库的大小也不会是无穷大的,那么我们就会有这样一
个需求:A线程提供了一定的数据量后就暂停,等待B线程全部取走之后(因为B再不来取的话,库就装不下
了),A线程再往其中添加数据,如此往复。这里存在两种方法;
1.资源库对象的wait()方法和notify()方法/notifyAll()方法
1 public class Share { 2 String name; 3 String sex; 4 //用empty来表示库中是否有数据 5 boolean empty = true; 6 7 // 线程A的任务,提供数据 8 synchronized public void product(String name, String sex) { 9 try { 10 while(!empty) { 11 //当库中数据不为空时,A线程不能向其添加数据,小憩一会儿 12 this.wait(); 13 } 14 //当库中数据为空时,A线程向其添加数据 15 this.name = name; 16 this.sex = sex; 17 //添加完成之后,更改库中数据状态为不空,并唤醒其他线程来拿数据 18 empty=false; 19 this.notifyAll(); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 24 } 25 26 // 线程B的任务,提取(显示)数据 27 synchronized public void show() { 28 try { 29 while(empty) { 30 //当库中数据为空时,B线程不能获取数据,小憩一会儿 31 this.wait(); 32 } 33 //当库中数据不为空时,B线程获取数据并打印 34 System.out.println("姓名:" + this.name + "性别:" + this.sex); 35 //拿完数据之后,更改库中数据状态为空,并唤醒其他线程继续写数据 36 empty=true; 37 this.notifyAll(); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 } 42 }
wait()方法和notifyAll()方法只能由同步监听器对象来调用,就是这里说的资源库对象。
2.同步锁(Lock)和Condition接口
之前讲线程同步时有说到同步锁的方法,这种方法是没有同步监听器对象的,那么上面的wait()等方法就不能用了,
但是不用担心,java5在推出同步锁的时候也为其通信控制提供了一个方法获得Condition对象,来实现通信控制
1 public class Share { 2 String name; 3 String sex; 4 //创建锁 5 final Lock lock = new ReentrantLock(); 6 //创建Condition对象 7 Condition condition = lock.newCondition(); 8 // 用empty来表示库中是否有数据 9 boolean empty = true; 10 11 // 线程A的任务,提供数据 12 public void product(String name, String sex) { 13 lock.lock();//上锁 14 try { 15 while (!empty) { 16 // 当库中数据不为空时,A线程不能向其添加数据,小憩一会儿 17 condition.await(); 18 } 19 // 当库中数据为空时,A线程向其添加数据 20 this.name = name; 21 this.sex = sex; 22 // 添加完成之后,更改库中数据状态为不空,并唤醒其他线程来拿数据 23 empty = false; 24 condition.signalAll(); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 lock.unlock();//解锁 29 } 30 31 // 线程B的任务,提取(显示)数据 32 public void show() { 33 lock.lock();//上锁 34 try { 35 while (empty) { 36 // 当库中数据为空时,B线程不能获取数据,小憩一会儿 37 condition.await(); 38 } 39 // 当库中数据不为空时,B线程获取数据并打印 40 System.out.println("姓名:" + this.name + "性别:" + this.sex); 41 // 拿完数据之后,更改库中数据状态为空,并唤醒其他线程继续写数据 42 empty = true; 43 condition.signalAll(); 44 } catch (InterruptedException e) { 45 e.printStackTrace(); 46 } 47 condition.signalAll();//解锁 48 } 49 }