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; ...
随机推荐
- 20155219 2016-2017-2 《Java程序设计》第3周学习总结
20155219 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 数组问题 -Scanner实例,猜数字. package src.week1; import ...
- 再回首 基本数据类型和 if语句
一 变量:(使用变量是不能加引号,要不就变成字符串了) 变量的命名规则: 1.数字,字母,下划线组成. 2.变量不能是数字开头 3.区分大小写 4.不要使用中文或者拼音 5.要有相应的意义 6.不能使 ...
- import sys
目录 sys模块的常见函数列表 1.sys.argv 2.sys.platform 3.sys.path 4.sys.exit(n) sys模块提供了一系列有关Python运行环境的变量和函数. 回到 ...
- 在java中(==)的用法
- 【java多线程】队列系统之LinkedBlockingQueue源码
转载:https://blog.csdn.net/tonywu1992/article/details/83419448 http://benjaminwhx.com/archives/ 1.简介 上 ...
- 【mybatis源码学习】mybtias一级,二级缓存
转载:https://www.cnblogs.com/ysocean/p/7342498.html mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解: ①.一级缓存是SqlSessi ...
- 【mybatis源码学习】mybtias基础组件-反射工具
一.JavaBean的规范 类中定义的成员变量也称为字段,属性则是通过getter/setter方法得到的,属性只与类中的方法有关,与是否存在对应成员变量没有关系. 属性的getter/setter方 ...
- MySQL DataType--数值类型
=========================================================MySQL常见的整数类型有:TINYINT: 占用8位空间SMALLINT: 占用16 ...
- Cassandra Demo--Python操作cassandra
================================================================ 创建keyspace和table CREATE KEYSPACE ex ...
- 使用nexus 管理pip 私有包
nexus 已经支持了对于python pip 包的管理(支持group,host,proxy) 这个是一个简单的使用docker 运行的demo,同时集成了s3 存储,以及 一个为了测试简单的自定义 ...