博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发编程_wait/notify和CountDownLatch的比较(三)
阅读量:7097 次
发布时间:2019-06-28

本文共 5269 字,大约阅读时间需要 17 分钟。

 

 1、wait/notify方法

package sync;import java.util.ArrayList;import java.util.List;public class WaitAndNotify {	private volatile static List list= new ArrayList();		private void add() {		list.add("wang");	}		private int size() {		return list.size();	}			public static void main(String[] args) {				final WaitAndNotify list1 = new WaitAndNotify();		/*		 * 1. 实例化一个Object对象当作锁,下面t1和t2竞争这把锁实现同步		 * 2. Object下面会有wait、notify方法,(面试经常问:Object下面有哪些方法,)		 * 3. 说明每个对象都有这两个方法,都可以当作锁		 */		final Object lock = new Object();				Thread t1 = new Thread(new Runnable() {			@Override			public void run() {				try {					synchronized (lock) {						for(int i = 0; i < 10; i++) {							list1.add();							System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素");							Thread.sleep(500);							if(list1.size() == 5) {								System.out.println("已经发出通知..");								//notify不释放锁,for循环还会继续执行								lock.notify();							}						}					}									} catch(InterruptedException e) {					e.printStackTrace();				}											}		}, "t1");				Thread t2 = new Thread(new Runnable() {			@Override			public void run() {				synchronized(lock) {					/*					 * 如果先执行t2线程,如果size不是5,就wait					 * wait会释放锁					 */					if(list1.size() != 5) {						try {							System.out.println("t2进入..");							Thread.sleep(3000);							lock.wait();						}catch(InterruptedException e) {							e.printStackTrace();						}					}					//					System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + "list size = 5,线程停止");					throw new RuntimeException();				}							}		}, "t2");				t2.start();		t1.start();	}}

 

输出结果:

t2进入..当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素已经发出通知..当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程:t1添加了一个元素当前线程收到通知:t2list size = 5,线程停止Exception in thread "t2" java.lang.RuntimeException	at sync.WaitAndNotify$2.run(WaitAndNotify.java:73)	at java.lang.Thread.run(Unknown Source)

  

代码解读:

第一步:执行t2线程,进入run方法,list.size不等于5,就lock.wait释放锁,t2进程等待,转而执行t1

第二步:执行t1进程,得到锁,执行for循环,当list.size等于5时,发出通知..唤醒t2进程,但是会继续执行完for循环,因为notify不释放锁

第三步:t2进程被唤醒,因此list.size已经等于10,不等于5,直接输出最后两行代码

 

wait/notify的方式弊端:

 

t2线程先start,因为其List的size!=5,所以执行lock.wait()释放对象锁,这样在t1线程就可以获得这把lock对象锁。

t1线程向List中添加元素,当List的size==5时,执行lock.notify(),发出唤醒通知,此时t1线程并不释放lock对象锁,所以这时t2虽然收到唤醒的通知,但是由于t1此时并未释放lock对象锁,所以t2只能一直等待,直到t1执行完毕释放lock对象锁,t2才能获取到lock对象锁,执行lock.wait();后面的代码。

 

 

 2、CountDownLatch方法

下面使用java.util.concurrent包下的类CountDownLatch对上面wait/notify方式的代码进行改造。

CountDownLatch机制不是用来保护共享资源或临界区,而是用来同步一个或多个执行任务的线程。

 

import java.util.ArrayList;  import java.util.List;  import java.util.Queue;  import java.util.concurrent.CountDownLatch;  import java.util.concurrent.LinkedBlockingDeque;  import java.util.concurrent.LinkedBlockingQueue;  /**  * wait notfiy 方法,wait释放锁,notfiy不释放锁  *  */  public class ListAdd2 {      private volatile static List list = new ArrayList();                public void add(){          list.add("abc");      }      public int size(){          return list.size();      }            public static void main(String[] args) {                    final ListAdd2 list2 = new ListAdd2();                    // 当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用          //final Object lock = new Object();                    final CountDownLatch countDownLatch = new CountDownLatch(1);                    Thread t1 = new Thread(new Runnable() {              @Override              public void run() {                  try {                      //synchronized (lock) {                          for(int i = 0; i <10; i++){                              list2.add();                              System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");                              Thread.sleep(500);                              if(list2.size() == 5){                                  System.out.println("已经发出通知..");                                  countDownLatch.countDown();                                  //lock.notify();//不释放对象锁                              }                          }                                             //}                  } catch (InterruptedException e) {                      e.printStackTrace();                  }                }          }, "t1");                    Thread t2 = new Thread(new Runnable() {              @Override              public void run() {                  //synchronized (lock) {                      if(list2.size() != 5){                          try {                              //System.out.println("t2进入...");                              //lock.wait();//释放对象锁                              countDownLatch.await();                          } catch (InterruptedException e) {                              e.printStackTrace();                          }                      }                      System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");                      throw new RuntimeException();                  //}              }          }, "t2");                       t2.start();//t2先启动          t1.start();                }        }

 

t2先启动,countDownLatch.await()方法进行阻塞。

t1启动后再运行过程中,当List的size==5时,执行countDownLatch.countDown()发出唤醒通知,

此时,t2接收到通知后,由于没有使用synchronized关键字涉及不到获取锁的问题,因此t2收到通知立即开始执行countDownLatch.await()后面的代码。

在Eclipse中console输出内容如下:

 

转载地址:http://nthql.baihongyu.com/

你可能感兴趣的文章
Linux命令模拟Http的get或post请求
查看>>
Navicat使用教程:使用Navicat Query Analyzer优化查询性能(第2部分)
查看>>
mongoDB 在windows平台下安装成系统服务
查看>>
linux学习第八周总结
查看>>
第二次测试题
查看>>
Java 处理异常 9 个最佳实践,你知道几个?
查看>>
Apache 不能列目录解决。
查看>>
如何永久的修改主机名
查看>>
NSSearchPathForDirectoriesInDomains用法(后台缓存)
查看>>
Jqurey 全选和全不选
查看>>
ELK日志收集平台部署
查看>>
软件公司员工辞职、人员流动大是必然
查看>>
勤快的love枫[ZJOI2007]
查看>>
Linux查看系统信息的一些命令及查看已安装软件包的命令
查看>>
poj1417 true liars(并查集 + DP)详解
查看>>
离散数学--二元关系总结
查看>>
HTML5 本地存储 localStorage、sessionStorage 的遍历、存储大小限制处理
查看>>
【leetcode】688. Knight Probability in Chessboard
查看>>
【leetcode】Maximum Product of Word Lengths
查看>>
C 工具库 GLib --- 提供多种高级的数据结构,如内存块、双向和单向链表、哈希表、动态字符串等...
查看>>