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 ...
随机推荐
- OpenResty 简介
OpenResty 简介 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台.我们知道开发 Nginx 的模块需要用 C 语言,同时还要熟悉它的源码,成本和门槛比较高.国人 ...
- github下载大文件太慢/失败
场景 github下载大文件,使用浏览器下载zip包到本地在下载到1G时失败, 使用 git clone ssh下载速度20k/s以下,已fq. 解决方法(亲测) 1.下载Github Desktop ...
- 神经网络中的降维和升维方法 (tensorflow & pytorch)
大名鼎鼎的UNet和我们经常看到的编解码器模型,他们的模型都是先将数据下采样,也称为特征提取,然后再将下采样后的特征恢复回原来的维度.这个特征提取的过程我们称为"下采样",这个恢复 ...
- 经典项目管理 OR 敏捷项目管理,我该怎么选?
CODING 项目协同近期为支持传统项目管理推出了「经典项目管理」.至此,CODING 已全面支持敏捷项目管理以及传统项目管理.那么问题来了,「经典项目管理」和「敏捷项目管理」,我该怎么选呢?本文将从 ...
- 了解一下RPC,为何诞生RPC,和HTTP有什么不同?
了解一下RPC,为何诞生RPC,和HTTP有什么不同? 开篇提问 什么是RPC? 为什么需要RPC,用来解决什么问题? RPC与HTTP有什么不同? 你知道几种RPC? 认识RPC RPC:Remot ...
- win7安装oracle11g和oracle client和pl/sql
一.安装oracle11g 1.下载Oracle 11g R2 for Windows的版本 下载地址:hhttps://www.oracle.com/technetwork/database/ent ...
- Mac Navicat premium 12 连接mysql8.0.21出现 'caching_sha2_password' 解决方案
1.通过命令 select user,plugin from user where user='root'; 我们可以发现加密方式是caching_sha2_password. 2. 修改查看加密方 ...
- 解决Tengine健康检查引起的TIME_WAIT堆积问题
简介: 解决Tengine健康检查引起的TIME_WAIT堆积问题 一. 问题背景 "服务上云后,我们的TCP端口基本上都处于TIME_WAIT的状态"."这个问题在线下 ...
- Java开发手册之编程规约
时隔一年多,再次开始更新博客,各位粉丝们久等了.大家是不是以为我像大多数开发者一样三分钟热度,坚持了一年半载就放弃了,其实不是.在过去的一年时间我学习了<Java编程思想>这本书,因为都是 ...
- 【ORA】ora-39700解决