第五章 并行模式与算法

1、单例模式

  • 是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统一个类只产生一个实例。
  • 对于频繁创建使用的对象可以省略new 操作花费的时间,可以减少系统开销。
  • 由于new 操作的次数减少,系统内存使用频率降低,这将减轻GC压力,缩短GC停顿时间。
  • 构造函数私有,instance对象需要是私有且静态的

2、不变模式

核心:一个对象一旦被创建,则它的内部状态将永远不会发生改变。

不变模式的实现:

  • 去除所有的setter方法以及所有修改自身属性的方法。
  • 属性设为私有,并且final标记,确保其不可修改。
  • 确保子类可以重载修改它的行为。
  • 有一个可以创建完整对象的构造函数。

使用不变模式的例子:元数据的包装类和String类

3、生产者消费者模式

  • 生产者线程负责提交用户请求,消费者线程负责具体处理生产者提交的任务,生产者和消费者之间则通过共享内存缓冲进行通信。
  • 生产者消费者模式中的内存缓存区,它做为生产者消费者之间的通信桥梁,避免了生产者和消费者之间的直接通信,从而将生产者和消费者进行解耦。
  • 缓冲区的主要功能是数据在多线程间的共享,此外通过该缓冲区可以缓解生产者和消费者间的性能差异。

    共享数据:

    package com.ecut.pattern;
    
    public class PCData {
    
        private final int intData;
    
        public PCData(String s) {
    intData = Integer.valueOf(s);
    } public PCData(int i) {
    intData = i;
    } @Override
    public String toString() { return "PCdata:" + intData;
    }
    }

    生产者:

    package com.ecut.pattern;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.atomic.AtomicInteger; public class Producer implements Runnable { private volatile boolean isRunning = true; private AtomicInteger count = new AtomicInteger(); private BlockingQueue<PCData> queue; public Producer(BlockingQueue<PCData> queue) {
    this.queue = queue;
    } @Override
    public void run() {
    while (isRunning) {
    PCData data = new PCData(count.incrementAndGet());
    if (!queue.offer(data)) {
    System.out.println(Thread.currentThread().getName() + "failed to put data:" + data);
    } else {
    System.out.println(Thread.currentThread().getName() + " product data :" + data);
    }
    }
    } public void stop() {
    isRunning = false;
    }
    }

    消费者:

    package com.ecut.pattern;
    
    import java.util.concurrent.BlockingQueue;
    
    public class Consumer implements Runnable {
    
        private BlockingQueue<PCData> queue;
    
        public Consumer(BlockingQueue<PCData> queue) {
    this.queue = queue;
    } @Override
    public void run() {
    try {
    while (true) {
    PCData pcData = queue.take();
    if (pcData != null) {
    System.out.println(Thread.currentThread().getName() + " consumer data " + pcData);
    }
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    Main函数:

    package com.ecut.pattern;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingDeque; public class Main { public static void main(String[] args) throws InterruptedException {
    BlockingQueue<PCData> blockingQueue = new LinkedBlockingDeque<PCData>(10);
    Producer producer1 = new Producer(blockingQueue);
    Producer producer2 = new Producer(blockingQueue);
    Producer producer3 = new Producer(blockingQueue);
    Consumer consumer1 = new Consumer(blockingQueue);
    Consumer consumer2 = new Consumer(blockingQueue);
    Consumer consumer3 = new Consumer(blockingQueue);
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(producer1);
    executorService.execute(producer2);
    executorService.execute(producer3);
    executorService.execute(consumer1);
    executorService.execute(consumer2);
    executorService.execute(consumer3);
    Thread.sleep(10000);
    producer1.stop();
    producer2.stop();
    producer3.stop();
    executorService.shutdown();
    }
    }

4、Future模式

  • Future模式的核心是异步调用,可以被调用者立即返回,让他在后台慢慢处理这个请求。调用者可以先处理其他任务。
  • RunnableFuture继承了Future和Runnable接口,其中run方法用于构造真实数据,它有一个具体实现类FutureTask类。FutureTask类内部run方法使调用Callable接口的run方法。
    package com.ecut.pattern;
    
    import java.util.concurrent.Callable;
    
    public class RealData implements Callable<String> {
    private String para; public RealData(String para) {
    this.para = para;
    } @Override
    public String call() throws Exception {
    StringBuffer stringBuffer = new StringBuffer();
    for(int i = 0 ; i< 10 ; i++){
    stringBuffer.append(para);
    }
    return stringBuffer.toString();
    }
    }

    FutureTest类:

    package com.ecut.pattern;
    
    import java.util.concurrent.*;
    
    public class FutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    //构造futureTask
    FutureTask<String> futureTask = new FutureTask<String>(new RealData("a"));
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    //执行futureTask实际上是调用的RealData的call方法
    executorService.submit(futureTask);
    System.out.println("请求完毕!");
    //异步调用,因此这里可以进行其他的业务处理
    Thread.sleep(2000);
    //如果call方法没有执行完则依然等待
    System.out.println("数据为" + futureTask.get());
    }
    }

    运行结果如下:

    请求完毕!
    数据为aaaaaaaaaa

5、并行流水线

并行流水线:将有依赖的操作分配在不同的线程进行计算。

package com.ecut.parallel;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; public class Pipeline { public static class Msg {
public double i;
public double j;
public String orgStr = null;
} public static class Plus implements Runnable { public static BlockingQueue<Msg> blockingQueue = new LinkedBlockingQueue<>(); @Override
public void run() {
try {
Msg msg = blockingQueue.take();
msg.j = msg.i + msg.j;
Multiply.blockingQueue.add(msg);
} catch (InterruptedException e) {
e.printStackTrace();
} }
} public static class Multiply implements Runnable { public static BlockingQueue<Msg> blockingQueue = new LinkedBlockingQueue<>(); @Override
public void run() {
try {
Msg msg = blockingQueue.take();
msg.j = msg.j * msg.i;
Div.blockingQueue.add(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static class Div implements Runnable { public static BlockingQueue<Msg> blockingQueue = new LinkedBlockingQueue<>(); @Override
public void run() {
try {
Msg msg = blockingQueue.take();
msg.j = msg.j / 2;
System.out.println(msg.orgStr + "=" + msg.j);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
for (int i = 1; i < 1000; i++) {
for (int j = 1; j < 1000; j++) {
Msg msg = new Msg();
msg.i = i;
msg.j = j;
msg.orgStr = "((" + i + "+" + j + ")" + "*" + i + ")/2";
Plus.blockingQueue.add(msg);
new Thread(new Plus()).start();
new Thread(new Multiply()).start();
new Thread(new Div()).start();
}
} }
}

6、并行排序

例子:奇偶排序、希尔排序

源码地址:

https://github.com/SaberZheng/concurrent-test

转载请于明显处标明出处:

https://www.cnblogs.com/AmyZheng/p/10481967.html

《实战Java高并发程序设计》读书笔记五的更多相关文章

  1. 【鸟哥的Linux私房菜】笔记1

    Linux是什么 从操作系统与cpu架构关系到linux  Richard Mathew Stallman GPL 关于GNU计划 Linux的发展 Linux的核心版本 Linux的特色 Linux ...

  2. 【鸟哥的Linux私房菜】笔记3

    正确地开机 最好不要使用root账号登陆!GNOME图形界面 View items as a list X WindowShell 文本交互界面bash是Shell的名称,Linux的默认壳程序就是b ...

  3. 【鸟哥的Linux私房菜】笔记2

    Linux的应用 学习资源整理 安装记录 >< 1.Linux的应用: 网络服务器 数据库 学术机构的高效运算任务 嵌入式系统 ... 2.挂载与磁盘分区 学习资源整理 学习 1.书上的网 ...

  4. 《鸟哥的Linux私房菜》笔记——02. 关于Linux

    Unix 历史 1969年以前:伟大的梦想--Bell, MIT 与 GE 的「Multics」系统 1969年:Ken Thompson 的小型 file server system 1973年:U ...

  5. 《鸟哥的Linux私房菜》笔记——03. 磁盘分区

    Everything is a file. 常见硬件对应于 Linux 下的文件(/dev目录下) 装置 装置在Linux内的档名 SCSI/SATA/U盘硬盘机 /dev/sd[a-p] U盘 /d ...

  6. 鸟哥的linux私房菜学习笔记 __ 命令与文件的搜寻

    连续输入两次[tab]按键就能够知道使用者有多少命令可以下达.那你知不知道这些命令的完整档名放在哪里?举例来说,ls 这个常用的命令放在哪里呢? 就透过 which 或 type 来找寻吧! 范例一: ...

  7. 【鸟哥的Linux私房菜】笔记

    操作系统核心的功能! 驱动程序与操作系统的关系 2. [计算机组成之组件] 3.CPU实际要处理的数据完全来自于主存储器,这是一个很重要的概念! 4.CPU是整个计算机系统最重要的部分,那么目前世界上 ...

  8. 《鸟哥的Linux私房菜》笔记——04. 简单命令行

    键入命令 [dmtsai@study ~]$ command [-options] parameter1 parameter2 ... 指令 選項 參數(1) 參數(2) 注意:有时也可以使用 + 放 ...

  9. 鸟哥的Linux私房菜学习笔记——文件权限与目录配置

    Linux的文件权限和目录配置 在linux中的每个用户必需属于一个组,不能独立于组外.在linux中每个文件有所有者.所在组.其它组的概念. (1)所有者 一般为文件的创建者,谁创建了该文件,就是天 ...

  10. 鸟哥的Linux私房菜学习笔记(1)

    2014/10/29 1.档案的权限管理分为三个部分: 拥有者.群组.其他 2.ls -al 命令可以看到档案的详细信息 3.档案的属性中由十个部分构成 第一个部分是档案类型 -代表档案.d代表文件夹 ...

随机推荐

  1. C++ 实例练习-替换原生数组

    C++ 实例练习-替换原生数组 main.cpp #include <stdio.h> #include "intarray.h" int main(int argc, ...

  2. 题解 P1203 【[USACO1.1]坏掉的项链Broken Necklace】

    [USACO1.1]坏掉的项链Broken Necklace 22892 破碎的项链 方法一:很容易想到枚举断点,再分别两头找,但是要注意很多细节 #include<iostream> # ...

  3. css 单位之px , em , rem

    px : Pixel像素单位.像素是相对显示器分辨率而言.em : 相对长度单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px).rem : 相对单 ...

  4. Web API幂等、超时优化

    幂等 当涉及业务数据的变更,不是简单的数据查询时, 在调用方相同条件有效重复请求时,就需要保持业务系统数据之间的一致性,不管请求多少次都会返回相同的结果. 比如一个订单支付接口,第一次请求返回支付成功 ...

  5. python之路面向对象2

    一.利用反射查看面向对象成员的归属 二.利用反射导入模块.查找类.创建对象.查找对象中的字段 三.静态字段 静态字段存在类中,把对象每个都有的存在类中就行了,只存一份 四.静态方法 静态方法中没有se ...

  6. 题解【POJ3252】Round Numbers

    Description The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, P ...

  7. 使用c#做前台页面

    1.有很多组件,组件右属性,事件 2.在table中,操作用的是图片 3.打开dialog时,其他窗体不能使用 4.在子窗体编辑完,对后台操作后,在父窗体加载一下数据

  8. docker 环境部署

    docker 查看所有容器 docker ps  -a docker 查看所有running 容器: docker ps docker 停止全部容器: docker stop $(docker ps  ...

  9. SQL基础语法—insert语句

    1 insert语句 insert语句用于插入数据到表中,其基本语法有以下三种: Syntax: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IG ...

  10. 记一次if控制器的使用

    1.添加if控制器 2.输入判断条件:常见的就是某个变量是不是等于某个值 3.或者用函数助手中的函数 每个版本jmeter函数助手的入口不同,我的直接在菜单上: 选择__jexl3,输入判断条件,点击 ...