java架构《并发线程中级篇》
java多线程的三大设计模式
本章主要记录java常见的三大设计模式,Future、Master-Worker和生产者-消费者模式。
一、Future模式
使用场景:数据可以不及时返回,到下一次实际要使用结果的之前,后台自动查询并返回。类似与Ajax异步加载。
原理:客户端发起请求,结果需要返回Data对象,当服务器收到请求以后,FutureData包装类实现Data接口,不查询数据库,直接返回结果。(核心)。然后后台自己开一个线程去查询数据库,RealData真
实数据类,也实现Data接口,并返回数据。当实际使用时。获取到返回的真实数据。

代码分析:
1 // FutureClient 客户端类:
2
3 public class FutureClient {
4
5 public Data request(final String queryStr){
6 //1 我想要一个代理对象(Data接口的实现类)先返回给发送请求的客户端,告诉他请求已经接收到,可以做其他的事情
7 final FutureData futureData = new FutureData();
8 //2 启动一个新的线程,去加载真实的数据,传递给这个代理对象
9 new Thread(new Runnable() {
10 @Override
11 public void run() {
12 //3 这个新的线程可以去慢慢的加载真实对象,然后传递给代理对象
13 RealData realData = new RealData(queryStr);
14 futureData.setRealData(realData);
15 }
16 }).start();
17 return futureData;
18 }
19
20
1 // Data类:
2
3
4
5 public interface Data {
6
7 String getRequest();
8
9 }
10
11
1 // FutureData类:
2
3 public class FutureData implements Data{
4
5 private RealData realData ;
6
7 private boolean isReady = false;
8
9 public synchronized void setRealData(RealData realData) {
10 //如果已经装载完毕了,就直接返回
11 if(isReady){
12 return;
13 }
14 //如果没装载,进行装载真实对象
15 this.realData = realData;
16 isReady = true;
17 //进行通知
18 notify();
19 }
20
21 @Override
22 public synchronized String getRequest() {
23 //如果没装载好 程序就一直处于阻塞状态
24 while(!isReady){
25 try {
26 wait();
27 } catch (InterruptedException e) {
28 e.printStackTrace();
29 }
30 }
31 //装载好直接获取数据即可
32 return this.realData.getRequest();
33 }
34
35
36
37 }
38
39
1 // RealData类:
2
3 public class RealData implements Data{
4
5 private String result ;
6
7 public RealData (String queryStr){
8 System.out.println("根据" + queryStr + "进行查询,这是一个很耗时的操作..");
9 try {
10 Thread.sleep(5000);
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 System.out.println("操作完毕,获取结果");
15 result = "查询结果";
16 }
17
18 @Override
19 public String getRequest() {
20 return result;
21 }
22
23 }
24
25
1 // Main测试类:
2
3 public class Main {
4
5 public static void main(String[] args) throws InterruptedException {
6
7 FutureClient fc = new FutureClient();
8 Data data = fc.request("请求参数");
9 System.out.println("请求发送成功!");
10 System.out.println("做其他的事情...");
11 String result = data.getRequest();
12 System.out.println(result);
13 }
14 }
二:Master-Worker模式(并行计算模式)
使用场景:互不影响的多任务时。返回结果需要共同返回。其好处是讲一个大任务分解成若干个小任务。并行执行,提高系统的吞吐量。
原理:核心思想是系统由两类进程协作工作;Master进程和Worker进程。Master进程负责接收和分配工作,Worker进程主要负责处理子任务。当各
个Worker进程处理完后。会将结果返回给Master,由Master做归纳和总结,并返回。


代码分析:
1 //Worker类:
2
3 public class Worker implements Runnable {
4
5 private ConcurrentLinkedQueue<Task> workQueue;
6 private ConcurrentHashMap<String, Object> resultMap;
7
8 public void setWorkQueue(ConcurrentLinkedQueue<Task> workQueue) {
9 this.workQueue = workQueue;
10 }
11
12 public void setResultMap(ConcurrentHashMap<String, Object> resultMap) {
13 this.resultMap = resultMap;
14 }
15
16 @Override
17 public void run() {
18 while(true){
19 Task input = this.workQueue.poll();
20 if(input == null) break;
21 Object output = handle(input);
22 this.resultMap.put(Integer.toString(input.getId()), output);
23 }
24 }
25
26 private Object handle(Task input) {
27 Object output = null;
28 try {
29 //处理任务的耗时。。 比如说进行操作数据库。。。
30 Thread.sleep(500);
31 output = input.getPrice(); //模拟把Task类的价格做为结果返回
32 } catch (InterruptedException e) {
33 e.printStackTrace();
34 }
35 return output;
36 }
37
38 }
39
40
1 //Master类:
2
3 public class Master {
4
5 //1 有一个盛放任务的容器
6 private ConcurrentLinkedQueue<Task> workQueue = new ConcurrentLinkedQueue<Task>();
7
8 //2 需要有一个盛放worker的集合
9 private HashMap<String, Thread> workers = new HashMap<String, Thread>();
10
11 //3 需要有一个盛放每一个worker执行任务的结果集合
12 private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<String, Object>();
13
14 //4 构造方法
15 public Master(Worker worker , int workerCount){
16 worker.setWorkQueue(this.workQueue);
17 worker.setResultMap(this.resultMap);
18
19 for(int i = 0; i < workerCount; i ++){
20 this.workers.put(Integer.toString(i), new Thread(worker));
21 }
22 }
23
24 //5 需要一个提交任务的方法
25 public void submit(Task task){
26 this.workQueue.add(task);
27 }
28
29 //6 需要有一个执行的方法,启动所有的worker方法去执行任务
30 public void execute(){
31 for(Map.Entry<String, Thread> me : workers.entrySet()){
32 me.getValue().start();
33 }
34 }
35
36 //7 判断是否运行结束的方法
37 public boolean isComplete() {
38 for(Map.Entry<String, Thread> me : workers.entrySet()){
39 if(me.getValue().getState() != Thread.State.TERMINATED){
40 return false;
41 }
42 }
43 return true;
44 }
45
46 //8 计算结果方法
47 public int getResult() {
48 int priceResult = 0;
49 for(Map.Entry<String, Object> me : resultMap.entrySet()){
50 priceResult += (Integer)me.getValue();
51 }
52 return priceResult;
53 }
54 }
1 // Task类:
2
3
4
5 public class Task {
6
7 private int id;
8 private int price ;
9 public int getId() {
10 return id;
11 }
12 public void setId(int id) {
13 this.id = id;
14 }
15 public int getPrice() {
16 return price;
17 }
18 public void setPrice(int price) {
19 this.price = price;
20 }
21 }
22
23
1 //main测试类:
2
3 public class Main {
4
5 public static void main(String[] args) {
6
7 int Processors= Runtime.getRuntime().availableProcessors(); //获取到当前电脑的线程数
8 System.out.println("当前电脑是"+Processors+"核");
9 Master master = new Master(new Worker(),Processors );
10 //Master master = new Master(new Worker(),20 ); //开20个线程
11 Random r = new Random();
12 for(int i = 1; i <= 100; i++){
13 Task t = new Task();
14 t.setId(i);
15 t.setPrice(r.nextInt(1000));
16 master.submit(t);
17 }
18 master.execute(); //执行任务
19 long start = System.currentTimeMillis();
20
21 while(true){
22 if(master.isComplete()){
23 long end = System.currentTimeMillis() - start;
24 int priceResult = master.getResult();
25 System.out.println("最终结果:" + priceResult + ", 执行时间:" + end);
26 break;
27 }
28 }
29 }
30 }
31
32
三:生产者-消费者模式
使用场景:消息中间件。

代码分析:
1 // main测试类:
2
3 public class Main {
4
5 public static void main(String[] args) throws Exception {
6 //内存缓冲区
7 BlockingQueue<Data> queue = new LinkedBlockingQueue<Data>(10);
8 //生产者
9 Provider p1 = new Provider(queue);
10 Provider p2 = new Provider(queue);
11 Provider p3 = new Provider(queue);
12 //消费者
13 Consumer c1 = new Consumer(queue);
14 Consumer c2 = new Consumer(queue);
15 Consumer c3 = new Consumer(queue);
16 //创建线程池运行,这是一个缓存的线程池,可以创建无穷大的线程,没有任务的时候不创建线程。空闲线程存活时间为60s(默认值)
17
18 ExecutorService cachePool = Executors.newCachedThreadPool();
19
20 cachePool.execute(p1);
21 cachePool.execute(p2);
22 cachePool.execute(p3);
23 cachePool.execute(c1);
24 cachePool.execute(c2);
25 cachePool.execute(c3);
26
27 try {
28 Thread.sleep(3000);
29 } catch (InterruptedException e) {
30 e.printStackTrace();
31 }
32 p1.stop();
33 p2.stop();
34 p3.stop();
35 try {
36 Thread.sleep(2000);
37 } catch (InterruptedException e) {
38 e.printStackTrace();
39 }
40 }
41
42 }
43
44
1 Data类:
2
3 public final class Data {
4
5 private String id;
6 private String name;
7
8 public Data(String id, String name){
9 this.id = id;
10 this.name = name;
11 }
12
13 public String getId() {
14 return id;
15 }
16
17 public void setId(String id) {
18 this.id = id;
19 }
20
21 public String getName() {
22 return name;
23 }
24
25 public void setName(String name) {
26 this.name = name;
27 }
28
29 @Override
30 public String toString(){
31 return "{id: " + id + ", name: " + name + "}";
32 }
33
34 }
35
36
1 //Provider成产者类:
2
3
4
5 public class Provider implements Runnable{
6
7 //共享缓存区
8 private BlockingQueue<Data> queue;
9 //多线程间是否启动变量,有强制从主内存中刷新的功能。即时返回线程的状态
10 private volatile boolean isRunning = true;
11 //id生成器
12 private static AtomicInteger count = new AtomicInteger();
13 //随机对象
14 private static Random r = new Random();
15
16 public Provider(BlockingQueue queue){
17 this.queue = queue;
18 }
19
20 @Override
21 public void run() {
22 while(isRunning){
23 try {
24 //随机休眠0 - 1000 毫秒 表示获取数据(产生数据的耗时)
25 Thread.sleep(r.nextInt(1000));
26 //获取的数据进行累计...
27 int id = count.incrementAndGet();
28 //比如通过一个getData方法获取了
29 Data data = new Data(Integer.toString(id), "数据" + id);
30 System.out.println("当前线程:" + Thread.currentThread().getName() + ", 获取了数据,id为:" + id + ", 进行装载到公共缓冲区中...");
31 if(!this.queue.offer(data, 2, TimeUnit.SECONDS)){
32 System.out.println("提交缓冲区数据失败....");
33 //do something... 比如重新提交
34 }
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38 }
39 }
40
41 public void stop(){
42 this.isRunning = false;
43 }
44
45 }
46
47
1 // ConSumber消费者类:
2
3
4
5 public class Consumer implements Runnable{
6
7 private BlockingQueue<Data> queue;
8
9 public Consumer(BlockingQueue queue){
10 this.queue = queue;
11 }
12
13 //随机对象
14 private static Random r = new Random();
15
16 @Override
17 public void run() {
18 while(true){
19 try {
20 //获取数据
21 Data data = this.queue.take();
22 //进行数据处理。休眠0 - 1000毫秒模拟耗时
23 Thread.sleep(r.nextInt(1000));
24 System.out.println("当前消费线程:" + Thread.currentThread().getName() + ", 消费成功,消费数据为id: " + data.getId());
25 } catch (InterruptedException e) {
26 e.printStackTrace();
27 }
28 }
29 }
30 }
31
32
java架构《并发线程中级篇》的更多相关文章
- java架构《并发线程高级篇四》
本章主要讲并发线程的常见的两种锁.重入锁和读写锁 一:重入锁(ReentrantLock) 概念:重入锁,在需要进行同步的代码加锁,但最后一定不要忘记释放锁,否则会造成锁永远不能释放,其他线程进不了 ...
- java架构《并发线程高级篇一》
本章主要记录讲解并发线程的线程池.java.util.concurrent工具包里面的工具类. 一:Executor框架: Executors创建线程池的方法: newFixedThreadPool( ...
- java架构《并发线程高级篇二》
本章主要记录讲解并发线程的线程池.使用Executor框架自定义线程池. 自定义线程池使用Queue队列所表示出来的形式: 1 ArrayBlockingQueue<Runnable>(3 ...
- java架构《并发线程高级篇三》
本章主要介绍和讲解concurrent.util里面的常用的工具类. 一.CountDownLatch使用:(用于阻塞主线程) 应用场景 :通知线程休眠和运行的工具类,是wait和notify的升级版 ...
- Java高并发 -- 线程池
Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...
- Java高并发--线程安全策略
Java高并发--线程安全策略 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 不可变对象 发布不可变对象可保证线程安全. 实现不可变对象有哪些要注意的地方?比如JDK ...
- Java并发-线程池篇-附场景分析
作者:汤圆 个人博客:javalover.cc 前言 前面我们在创建线程时,都是直接new Thread(): 这样短期来看是没有问题的,但是一旦业务量增长,线程数过多,就有可能导致内存异常OOM,C ...
- Java高并发与多线程(四)-----锁
今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...
- Java之创建线程的方式四:使用线程池
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.c ...
随机推荐
- Spring Cloud是什么鬼?
研究了一段时间Spring Boot了准备向Spring Cloud进发,公司架构和项目也全面拥抱了Spring Cloud.在使用了一段时间后发现Spring Cloud从技术架构上降低了对大型系统 ...
- redis加锁的几种实现
redis加锁的几种实现 2017/09/21 1. redis加锁分类 redis能用的的加锁命令分表是INCR.SETNX.SET 2. 第一种锁命令INCR 这种加锁的思路是, key 不存在, ...
- 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇
前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...
- ConcurrentHashMap 并发之美
一.前言 她如暴风雨中的一叶扁舟,在高并发的大风大浪下疾驰而过,眼看就要被湮灭,却又在绝境中绝处逢生 编写一套即稳定.高效.且支持并发的代码,不说难如登天,却也绝非易事. 一直有小伙伴向我咨询关于Co ...
- JVM内存模型总结,有各版本JDK对比、有元空间OOM监控案例、有Java版虚拟机,综合实践学习!
作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...
- 使用IDEA构建Spring Boot项目简单实例
一.介绍 它的目标是简化Spring应用和服务的创建.开发与部署,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用的微服务功能,可以和spring cloud联合部署. Spring Boot ...
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB API重构)--学习笔记
2.5.8 MongoDB -- API重构 Lighter.Domain Lighter.Application.Contract Lighter.Application LighterApi Li ...
- vue的八个生命周期
1.beforeCreate: 创建Vue实例之前(只有默认的一些生命周期和默认的一些事件,data和methods还没有被初始化) 2.Create: 数据已经在data方法中初始化了,计算属性,事 ...
- 全网最牛X的!!! MySQL两阶段提交串讲
目录 一.吹个牛 二.事务及它的特性 三.简单看下两阶段提交的流程 四.两阶段写日志用意? 五.加餐:sync_binlog = 1 问题 六.如何判断binlog和redolog是否达成了一致 七. ...
- Spring(1) --入门(IoC,AOP)
说说你对spring的理解? Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题.Spring框架主要提供了IoC容器 ...