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; ...
随机推荐
- hdu 1280 堆排序
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- BinarySearch(Java)
private int binarySearch(int[] input, int target) { if (input == null) { return -1; } int index1 = 0 ...
- java黑魔法-反射机制-02-通过Java反射调用其他类方法
package com.aaron.reflect; import java.lang.reflect.Method; import java.lang.reflect.InvocationTarge ...
- 如何取消noarch.rpm包
有一次部署zabbix服务器,不小心rpm -ivh zabbix的el7版本的rpm了,但是我的系统是centos6.5的,所以就尴尬了 rpm -ivh http://repo.zabbix.co ...
- Linux系统运维故障排查
一.思路 1.处理问题要求 2.一般思路 二.具体问题 1.网络问题 (1)网络不通 (2)网络很慢 2.硬件问题 3.操作系统问题 (1)系统无法正常启动 (2)系统运行慢或死机 4.服务或程序问题 ...
- MySQL 5.7新特性之在线收缩undo表空间
1. MySQL 5.5时代的undo log 在MySQL5.5以及之前,大家会发现随着数据库上线时间越来越长,ibdata1文件(即InnoDB的共享表空间,或者系统表空间)会越来越大,这会造成2 ...
- yum和编译两种方式升级or降级Centos内核
http://blog.51cto.com/renzhiyuan/1882599 今天探讨用yum和编译两种方式升级或者降级内核版本: 升级:比如玩kvm,docker等虚拟化,centos内核则升级 ...
- makedepend: command not found(转)
makedepend: command not found 解决方案: 修改Makefile MAKEDEPEND=$(CC) -M 参考: When I set CROSS_COMPILE, `MA ...
- Jmeter使用自定义编写代码
原文地址:http://blog.csdn.net/li_ok/article/details/1487685 我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如 ...
- Spring Cloud Zuul 快速入门
Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...