互联网架构(2):并发编程--并发编程的设计模式
来源:互联网 发布:中国房地产未来知乎 编辑:程序博客网 时间:2024/04/28 04:08
2 并发编程的设计模式
(1)Future模式
该模式主要用于并行处理多个互不影响的请求,最后将结果汇总的业务。可以对多个不同的请求启动多个不同的线程,然后在线程中独立去获取想要的结果,等到真正需要使用该数据的时候才会获取到真正的结果。
下面是模拟的Future模式,(JDK已经提供了一些Future实现类,直接使用即可)
FutureClient.java
/** * 核心处理类,对请求启用独立线程 * @author jliu10 * */public class FutureClient{ public Data request(final String condition){ //创建一个数据包装对象 final FutureData futureData = new FutureData(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub //业务处理,请求数据 RealData realData = new RealData(); realData.request(condition); //将真实的结果数据设置到Future数据包装对象中 futureData.setRealData(realData); } }).start(); //返回数据包装对象,此时返回的包装对象是虚拟的,因为在线程没有执行完成之前,即futureData.setRealData(realData);调用之前,该对象是没有真实数据的 return futureData; }}
FutureData.java
/** * Future数据包装对象,利用notify和wait来阻塞请求,以确保最终能够获取到数据 * @author jliu10 */public class FutureData implements Data{ private RealData realData;//真实数据 private boolean isReady = false;//是否已经加载成功 /** * 设置真实数据 * @param realData */ public synchronized void setRealData(RealData realData){ if( isReady ){ //如果已经设置结果了,直接返回 return; } //设置结果对象 this.realData = realData; isReady = true; //唤醒获取数据的线程 System.out.println("数据准备完成,唤醒等待数据的线程..."); notify(); } @Override public synchronized String getRequest() { // TODO Auto-generated method stub while(!isReady){//如果还没有设置结果,进入等待,等待结果设置成功 try { System.out.println("数据还没有准备好,等待数据..."); wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return this.realData.getRequest(); }}
RealData.java
/** * 真实数据结果对象 * @author jliu10 */public class RealData implements Data { private String result = null; /** * 请求数据,真实场景中可能需要请求数据等操作,此处模拟耗时5s * @param condition */ public void request(String condition){ System.out.println("数据库获取数据,数据条件是:" + condition); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } result = "我是返回结果数据."; System.out.println("获取数据成功."); } @Override public String getRequest() { // TODO Auto-generated method stub return this.result; }}
Data.java
/** * 数据接口,需事先数据返回方法 * @author jliu10 */public interface Data { String getRequest();}
Main.java
/** * 模拟主函数 * @author jliu10 */public class Main { public static void main(String[] args) { //请求 FutureClient client = new FutureClient(); //future处理类返回虚拟结果 Data data = client.request("请求数据..."); System.out.println("请求发送成功..."); System.out.println("处理其他逻辑..."); try { Thread.sleep(2000);//模拟耗时2秒 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("使用请求的数据..."); String realData = data.getRequest(); System.out.println("数据结果是:" + realData); }}
result
请求发送成功...处理其他逻辑...数据库获取数据,数据条件是:请求数据...使用请求的数据...数据还没有准备好,等待数据...获取数据成功.数据准备完成,唤醒等待数据的线程...数据结果是:我是返回结果数据.
(2)Master-Worker模式
常用的并行计算模式。他的核心思想是系统由两类进程协作工作:Master进程和Worker进程。Master负责接收和分配任务,Worker负责处理子任务。当各个Worker子进程处理完成后,会将结果返回给Master,由Master做归纳和总结。其好处是能将一个大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量。
模拟Master-Worker模式
Master.java
import java.util.HashMap;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentLinkedQueue;/** * 1、使用高性能的并发队列来承装所有的任务,推荐:ConcurrentLinkedQueue * 2、使用一个容器来承装所有的Worker对象,不需要并发 * 3、使用并发类容器来接收work的返回结果,为了能够查寻到是哪一个work的结果,推荐使用Map类容器 * @author jliu10 * */public class Master { //高性能无锁并发队列,用来接收任务 private final ConcurrentLinkedQueue<Job> jobsQueue = new ConcurrentLinkedQueue<>(); //用来存放所有的work private Map<String, Thread> workersMap = new HashMap<String, Thread>(); //用来承装每一个worker并发处理任务的结果集 private final ConcurrentHashMap<String, Object> resultsMap = new ConcurrentHashMap<String, Object>(); public Master(Worker worker, int workerCount) { //将master的任务队列和结果集传入worker worker.setMasterJobsQueue(this.jobsQueue); worker.setMasterResultsMap(this.resultsMap); for (int i = 0; i < workerCount; i++) { //key表示每一个worker的名字, value表示线程执行对象 workersMap.put("worker-" + i, new Thread(worker)); } } /** * 提交方法 */ public void submit(Job job){ this.jobsQueue.add(job); } /** * 执行方法,启动Master应用程序,让所有的Worker开始工作 */ public void execute(){ for(Map.Entry<String, Thread> me : workersMap.entrySet() ){ me.getValue().start(); } } /** * 判断线程是否执行完毕 * @return */ public boolean isComplete() { // TODO Auto-generated method stub for(Map.Entry<String, Thread> me : workersMap.entrySet() ){ if(me.getValue().getState() != Thread.State.TERMINATED){ return false; } } return true; } public int getResult() { // TODO Auto-generated method stub int ret = 0; for(Map.Entry<String, Object> me : resultsMap.entrySet()){ ret += (Integer)me.getValue(); } return ret; }}
Worker.java
import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentLinkedQueue;/** * 1、每一个Worker为一个线程,所以必须要实现Runnable接口 * 2、每一个Worker必须要有Master的ConcurrentLinkedQueue的引用,用于从中获取任务 * 3、每一个Worker必须要有Master的ConcurrentHashMap的引用,用来将Worker的处理结果返回给Master * @author jliu10 * */public class Worker implements Runnable { private ConcurrentLinkedQueue<Job> masterJobsQueue; private ConcurrentHashMap<String, Object> masterResultsMap; public void setMasterJobsQueue(ConcurrentLinkedQueue<Job> masterJobsQueue) { this.masterJobsQueue = masterJobsQueue; } public void setMasterResultsMap( ConcurrentHashMap<String, Object> masterResultsMap) { this.masterResultsMap = masterResultsMap; } /** *子类重写该方法用以实现自己的业务逻辑 */ public Object handle(Job job){ return null; } @Override public void run() { // TODO Auto-generated method stub while (true) { //从队列中取一个任务开始执行 Job job = this.masterJobsQueue.poll(); //如果队列中没有任务了,则退出处理 if( null == job ){ break; } Object object = this.handle(job); this.masterResultsMap.put(Integer.toString(job.getId()), object); } }}
MyWorker.java
public class MyWorker extends Worker { /** * 处理业务逻辑的方法 */ @Override public Object handle(Job job) { Object output = null; // TODO Auto-generated method stub try { //表示处理job任务,可能是数据的加工,也可能是操作数据库,此处用休眠做模拟,处理结果为output Thread.sleep(500); output = job.getPrice(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return output; }}
(3)生产者-消费者模式
生产者和消费者也是一个非常经典的多线程模式,我们在实际的开发中应用非常广泛的思想理念。在生成-消费模式中:通常由两类线程,即若干个生产者的线程和若干个消费者的线程。生产者线程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务,在生产者和消费者之间通过共享内存缓存进行通信。
Provider.java
import java.util.Random;import java.util.concurrent.BlockingQueue;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;/** * 生产者 * @author jliu10 */public class Provider implements Runnable{ //公共缓存区 private BlockingQueue<Data> queue; //是否继续运行 private volatile boolean isRunning = true; //静态变量,用来模拟数据 private static AtomicInteger count = new AtomicInteger(0); private static Random r = new Random(); public Provider(BlockingQueue<Data> queue) { // TODO Auto-generated constructor stub this.queue = queue; } @Override public void run() { // TODO Auto-generated method stub while(isRunning){ try { //模拟生产数据,可以是从数据库获取 Thread.sleep(r.nextInt(1000)); int id = count.incrementAndGet(); Data data = new Data(Integer.toString(id), "数据-" + id); System.out.println("当前线程:" + Thread.currentThread().getName() + " ,获取了数据,id为:" + id + ", 进行装载数据到缓冲区..."); //将数据插入到公共缓冲区,2s超时 if(!this.queue.offer(data, 2, TimeUnit.SECONDS)){ System.out.println("提交数据到缓冲区失败..."); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void stop() { // TODO Auto-generated method stub this.isRunning = false; }}
Consumer.java
import java.util.Random;import java.util.concurrent.BlockingQueue;/** * 消费者 * @author jliu10 */public class Consumer implements Runnable{ //公共缓存区 private BlockingQueue<Data> queue; private static Random r = new Random(); public Consumer(BlockingQueue<Data> queue) { // TODO Auto-generated constructor stub this.queue = queue; } @Override public void run() { // TODO Auto-generated method stub while(true){ try { //从公共缓冲区获取数据进行消费 Data data = this.queue.take(); //模拟消费数据 Thread.sleep(r.nextInt(1000)); System.out.println("当前消费线程:" + Thread.currentThread().getName() + ", 消费成功,消费数据id:" + data.getId()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}
Main.java
import java.util.concurrent.BlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;/** * 主测试函数 * @author jliu10 */public class Main { public static void main(String[] args) { //内存缓冲区, LinkedBlockingQueue内部实现了读写分离锁,可以是读写完全并行 BlockingQueue<Data> blockingQueue = new LinkedBlockingQueue<Data>(10); //生产者 Provider p1 = new Provider(blockingQueue); Provider p2 = new Provider(blockingQueue); Provider p3 = new Provider(blockingQueue); //消费者 Consumer c1 = new Consumer(blockingQueue); Consumer c2 = new Consumer(blockingQueue); Consumer c3 = new Consumer(blockingQueue); //创建线程池运行 ExecutorService cachPool = Executors.newCachedThreadPool(); cachPool.execute(p1); cachPool.execute(p2); cachPool.execute(p3); cachPool.execute(c1); cachPool.execute(c2); cachPool.execute(c3); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } p1.stop(); p2.stop(); p3.stop(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
阅读全文
0 0
- 互联网架构(2):并发编程--并发编程的设计模式
- 互联网架构(5):并发编程--锁
- 互联网架构(6):并发编程--Disruptor并发框架
- 互联网高并发架构的8种设计模式演化
- 互联网架构(1):并发编程--多线程基础
- 互联网架构(3):并发编程--线程池
- 互联网架构(4):并发编程--Concurrent.util工具类
- JAVA并发编程--并发模式
- Java并发编程设计原则与模式
- 《并发编程设计模式》序言之概念
- 并发编程设计模式--Immutable Object
- java并发编程设计
- 互联网架构的高并发
- 互联网架构设计 (高并发高可用性)
- 并发编程中的NUMA架构
- 并发编程的四种模式
- Java 并发编程 多线程的交互模式
- 【Linux的高级应用编程】网络编程中并发服务器的设计模式
- java多线程—优先级反转问题
- C++/MFC-Spin
- Android热补丁之AndFix原理解析
- 【iOS】点击按钮Button,更变标签文字Label的颜色
- 【坑爹微信】微信JSSDK图片上传问题和解决
- 互联网架构(2):并发编程--并发编程的设计模式
- oracle设置某一个字段为当前时间
- jquery还原rowspan 并取数据
- 二维码生成方式
- Python 字符编码
- 数据结构——滑动窗口练习
- CentOS 安装gdb 7.12
- linux 内核配置详解
- 关于ajax已经成功了,却报404的错误的问题