java高并发编程(二)
马士兵java并发编程的代码,照抄过来,做个记录。
一、分析下面面试题
/**
* 曾经的面试题:(淘宝?)
* 实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
*
* 分析下面这个程序,能完成这个功能吗?
* @author mashibing
*/
package yxxy.c_019; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; public class MyContainer1 { List lists = new ArrayList(); public void add(Object o) {
lists.add(o);
} public int size() {
return lists.size();
} public static void main(String[] args) {
MyContainer1 c = new MyContainer1(); new Thread(() -> {
for(int i=0; i<10; i++) {
c.add(new Object());
System.out.println("add " + i); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1").start(); new Thread(() -> {
while(true) {
if(c.size() == 5) {
break;
}
}
System.out.println("t2 结束");
}, "t2").start();
}
}
/**
* 曾经的面试题:(淘宝?)
* 实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
*
* 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
* @author mashibing
*/
package yxxy.c_019; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; public class MyContainer2 { //添加volatile,使t2能够得到通知
volatile List lists = new ArrayList(); public void add(Object o) {
lists.add(o);
} public int size() {
return lists.size();
} public static void main(String[] args) {
MyContainer2 c = new MyContainer2(); new Thread(() -> {
for(int i=0; i<10; i++) {
c.add(new Object());
System.out.println("add " + i); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1").start(); new Thread(() -> {
while(true) {
if(c.size() == 5) {
break;
}
}
System.out.println("t2 结束");
}, "t2").start();
}
}
但是上面代码还存在两个问题:
1)由于没加同步,c.size()等于5的时候,假如另外一个线程又往上增加了1个,实际上这时候已经等于6了才break,所以不是很精确;
2)浪费CPU,t2线程的死循环很浪费cpu
三、使用wait和notify
/**
* 曾经的面试题:(淘宝?)
* 实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
*
* 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
*
* 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
* 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
*
* 阅读下面的程序,并分析输出结果
* 可以读到输出结果并不是size=5时t2退出,而是t1结束时t2才接收到通知而退出
* 想想这是为什么?
* @author mashibing
*/
package yxxy.c_019; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; public class MyContainer3 { //添加volatile,使t2能够得到通知
volatile List lists = new ArrayList(); public void add(Object o) {
lists.add(o);
} public int size() {
return lists.size();
} public static void main(String[] args) {
MyContainer3 c = new MyContainer3(); final Object lock = new Object(); new Thread(() -> {
synchronized(lock) {
System.out.println("t2启动");
if(c.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2 结束");
} }, "t2").start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
} new Thread(() -> {
System.out.println("t1启动");
synchronized(lock) {
for(int i=0; i<10; i++) {
c.add(new Object());
System.out.println("add " + i); if(c.size() == 5) {
lock.notify();
} try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t1").start(); }
}
分析:
1)解释wait和notify方法:

四、
/**
* 曾经的面试题:(淘宝?)
* 实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
*
* 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
*
* 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
* 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
*
* 阅读下面的程序,并分析输出结果
* 可以读到输出结果并不是size=5时t2退出,而是t1结束时t2才接收到通知而退出
* 想想这是为什么?
*
* notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
* 整个通信过程比较繁琐
* @author mashibing
*/
package yxxy.c_019; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; public class MyContainer4 { //添加volatile,使t2能够得到通知
volatile List lists = new ArrayList(); public void add(Object o) {
lists.add(o);
} public int size() {
return lists.size();
} public static void main(String[] args) {
MyContainer4 c = new MyContainer4(); final Object lock = new Object(); new Thread(() -> {
synchronized(lock) {
System.out.println("t2启动");
if(c.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2 结束");
//通知t1继续执行
lock.notify();
} }, "t2").start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
} new Thread(() -> {
System.out.println("t1启动");
synchronized(lock) {
for(int i=0; i<10; i++) {
c.add(new Object());
System.out.println("add " + i); if(c.size() == 5) {
lock.notify();
//释放锁,让t2得以执行
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t1").start(); }
}
流程图:

上面的通信过程太繁琐了,有没有简单点的办法?
五、
/**
* 曾经的面试题:(淘宝?)
* 实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
*
* 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
*
* 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
* 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
*
* 阅读下面的程序,并分析输出结果
* 可以读到输出结果并不是size=5时t2退出,而是t1结束时t2才接收到通知而退出
* 想想这是为什么?
*
* notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
* 整个通信过程比较繁琐
*
* 使用Latch(门闩)替代wait notify来进行通知
* 好处是通信方式简单,同时也可以指定等待时间
* 使用await和countdown方法替代wait和notify
* CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行
* 当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify就显得太重了
* 这时应该考虑countdownlatch/cyclicbarrier/semaphore
* @author mashibing
*/
package yxxy.c_019; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; public class MyContainer5 { // 添加volatile,使t2能够得到通知
volatile List lists = new ArrayList(); public void add(Object o) {
lists.add(o);
} public int size() {
return lists.size();
} public static void main(String[] args) {
MyContainer5 c = new MyContainer5(); CountDownLatch latch = new CountDownLatch(1); new Thread(() -> {
System.out.println("t2启动");
if (c.size() != 5) {
try {
latch.await(); //也可以指定等待时间
//latch.await(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2 结束"); }, "t2").start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
} new Thread(() -> {
System.out.println("t1启动");
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i); if (c.size() == 5) {
// 打开门闩,让t2得以执行
latch.countDown();
} try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }, "t1").start(); }
}
java高并发编程(二)的更多相关文章
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- java高并发编程(一)
读马士兵java高并发编程,引用他的代码,做个记录. 一.分析下面程序输出: /** * 分析一下这个程序的输出 * @author mashibing */ package yxxy.c_005; ...
- 关于Java高并发编程你需要知道的“升段攻略”
关于Java高并发编程你需要知道的"升段攻略" 基础 Thread对象调用start()方法包含的步骤 通过jvm告诉操作系统创建Thread 操作系统开辟内存并使用Windows ...
- Java高并发编程基础三大利器之CountDownLatch
引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...
- java高并发编程(三)
java高并发主要有三块知识点: synchronizer:同步器,在多个线程之间互相之间怎么进行通讯,同步等: 同步容器:jdk提供了同步性的容器,比如concurrentMap,concurren ...
- java高并发编程(五)线程池
摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...
- java高并发编程(四)高并发的一些容器
摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...
- [高并发]Java高并发编程系列开山篇--线程实现
Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...
- Java高并发编程(四)
一.Executor执行器 1.Executor接口,java线程池框架中的顶层接口,提供一个execute方法来执行任务 import java.util.concurrent.Executor; ...
随机推荐
- 2018.4.23 git常用操作命令收集(转)
Git常用操作命令收集: 1. 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git 查看远程仓库:$ git remote -v ...
- LeetCode–Flip Game
You are playing the following Flip Game with your friend: Given a string that contains only these tw ...
- JS 冒泡排序法 输出最大值
<html lang="en-US"> <head> <meta charset="UTF-8"> <title> ...
- VM安装系统时提示硬件不支持(unsupported hardware detected)
修改一下虚拟机配置,把CD/DVD中使用的autoinst.iso替换成需要安装的系统镜像文件 然而,后面发现还是会报这个错,不过,却可以正常安装下去.但是如果不修改这里的话,安装系统时会出错
- 手动安装python库
有些时候由于工作环境的限制如proxy,不能自动安装python 的第三方的库(用python –m pip install package).在这个情况下,只能自己手动安装.以xlwt-1.3.0. ...
- Docker网络解决方案-Flannel(转)
转自https://www.cnblogs.com/kevingrace/p/6859114.html Docker跨主机容器间网络通信实现的工具有Pipework.Flannel.Weave.Ope ...
- 持续集成--Jenkins--2
安装sonar Scanner 打开http://www.sonarqube.org/官网 找到下面扫描器 通过这个扫描器可以分析代码分析 因此你也的安装这个扫描器 上传sonar-scanner-2 ...
- Java基础语法 第3节 常用软件安装-Webstorm
Webstorm是专用于web开发的号称最好的的编辑器,使用起来很方便. 一.安装 1.去官网下载正版安装包,官网地址:http://www.jetbrains.com/webstorm/ 2.开始安 ...
- mina基础知识整理
一. 简介: Apache Mina Server 是一个网络通信应用框架,Mina 可以帮助我们快速开发高性能.高扩展性的网络通信应用,Mina 提供了事件驱动.异步(Mina 的异步 I ...
- [转]浅谈UML的概念和模型之UML九种图
目录: UML的视图 UML的九种图 UML中类间的关系 上文我们介绍了,UML的视图,在每一种视图中都包含一个或多种图.本文我们重点讲解UML每种图的细节问题: 1.用例图(use case dia ...