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(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//synchronized (lock) {
for(int i = ; i <; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep();
if(list2.size() == ){
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() != ){
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输出内容如下:

Java并发编程_wait/notify和CountDownLatch的比较(三)的更多相关文章

  1. JAVA并发编程之倒计数器CountDownLatch

    CountDownLatch 的使用场景:在主线程中开启多线程去并行执行任务,并且主线程需要等待所有子线程执行完毕后汇总返回结果. 我把源码中的英文注释全部删除,写上自己的注释.就剩下 70 行不到的 ...

  2. Java并发编程:Semaphore、CountDownLatch、CyclicBarrier

    首先我们来实现一个功能:当我们启动一个系统的时候需要初始化许多数据,这时候我们可能需要启动很多线程来进行数据的初始化,只有这些系统初始化结束之后才能够启动系统.其实在Java的类库中已经提供了Sema ...

  3. Java 并发编程实践基础 读书笔记: 第三章 使用 JDK 并发包构建程序

    一,JDK并发包实际上就是指java.util.concurrent包里面的那些类和接口等 主要分为以下几类: 1,原子量:2,并发集合:3,同步器:4,可重入锁:5,线程池 二,原子量 原子变量主要 ...

  4. Java并发编程(二)创建线程的三种方法

    进程与线程 1.  进程 进程和代码之间的关系就像音乐和乐谱之间的关系一样,演奏结束的时候音乐就不存在了但乐谱还在:程序执行结束的时候进程就消失了但代码还在,而计算机就是代码的演奏家. 2. 线程 线 ...

  5. 【Java并发编程】并发编程大合集-值得收藏

    http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...

  6. 【Java并发编程】并发编程大合集

    转载自:http://blog.csdn.net/ns_code/article/details/17539599 为了方便各位网友学习以及方便自己复习之用,将Java并发编程系列内容系列内容按照由浅 ...

  7. 【Java并发编程实战】-----“J.U.C”:CountDownlatch

    上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...

  8. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  9. Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

随机推荐

  1. Appium的工作原理

    把我们写的python语言代码,看做客户端 通过客户端向appium服务器发送请求 appium服务器把我们的代码转换成手机可以识别的指令 然后把指令发给手机,手机根据指令做出相应的操作 最后手机把操 ...

  2. C#清除HTML样式

    C#清除HTML样式 需求说明: 网站开发时我们经常用一个富文本控件让用户自己编辑新闻内容和新闻格式,然后将HTML代码一并保存到数据库中. 然后显示文章列表的时候只需要显示一个文章摘要,所以我们就计 ...

  3. MySql常用函数全部汇总

    MySQL数据库中提供了很丰富的函数.MySQL函数包括数学函数.字符串函数.日期和时间函数.条件判断函数.系统信息函数.加密函数.格式化函数等.通过这些函数,可以简化用户的操作.例如,字符串连接函数 ...

  4. 数据结构(C语言版)-第5章 树和二叉树

    5.1  树和二叉树的定义 树(Tree)是n(n≥0)个结点的有限集,它或为空树(n = 0):或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点:(2)除根结点以外的其余结点可分为m(m& ...

  5. HTML第十章总结

    前言 这一章节讲了以下内容: 两个新的 HTML elelments:它们是 <div>和 <span>,使用这两个 element 可以使得 HTML 有更加 serious ...

  6. FetchType.LAZY和FetchType.EAGER什么区别

    1.FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载. 2.FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载. ...

  7. scala文件读取报错“java.nio.charset.MalformedInputException: Input length = 1”

    今天写spark程序的时候遇到了一个问题就是,读取文件的时候报了一个错:“Exception in thread "main" java.nio.charset.Malformed ...

  8. English trip V1 - B 6.Where Are You From? Teacher:Patrick Key: 一般疑问句和否定句中的be动词

    In this lesson you will learn to talk about countries and languages.  本节课你将学习到关于谈论城市和语言 课上内容(Lesson) ...

  9. 内核开启VF小结

    2017-8-29 16:33:40 内核开启VF小结: 1. eth2上创建4个VFecho 4 > /sys/class/net/eth2/device/sriov_numvfs2. 关闭e ...

  10. 6 Django REST framework JWT 和登录功能实现

    JWT 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证. 我们不再使用Session认证机制,而使用Json Web Token认证机制. Json web token ( ...