java设计模式并发_[高并发Java 七] 并发设计模式

[高并发Java 七] 并发设计模式

[高并发Java 七] 并发设计模式

为什么80%的码农都做不了架构师?>>>

aa15a3967fe879cafbad81ddaa08b523.png

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题 ,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建筑设计领 域引入到计算机科学的。

著名的4人帮: Erich Gamma,Richard Helm, Ralph Johnson ,John Vlissides (Gof)

《设计模式:可复用面向对象软件的基础》收录23种模式

单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为

比如:全局信息配置

单例模式最简单的实现:

public class Singleton {

private Singleton() {

System.out.println("Singleton is create");

}

private static Singleton instance = new Singleton();

public static Singleton getInstance() {

return instance;

}

} 由私有构造方法和static来确定唯一性。

缺点:何时产生实例 不好控制

虽然我们知道,在类Singleton第一次被加载的时候,就产生了一个实例。

但是如果这个类中有其他属性

public class Singleton {

public static int STATUS=1;

private Singleton() {

System.out.println("Singleton is create");

}

private static Singleton instance = new Singleton();

public static Singleton getInstance() {

return instance;

}

} 当使用

System.out.println(Singleton.STATUS); 这个实例就被产生了。也许此时你并不希望产生这个实例。

如果系统特别在意这个问题,这种单例的实现方法就不太好。

第二种单例模式的解决方式:

public class Singleton {

private Singleton() {

System.out.println("Singleton is create");

}

private static Singleton instance = null;

public static synchronized Singleton getInstance() {

if (instance == null)

instance = new Singleton();

return instance;

}

} 让instance只有在调用getInstance()方式时被创建,并且通过synchronized来确保线程安全。

这样就控制了何时创建实例。

这种方法是延迟加载的典型。

但是有一个问题就是,在高并发的场景下性能会有影响,虽然只有一个判断就return了,但是在并发量很高的情况下,或多或少都会有点影响,因为都要去拿synchronized的锁。

为了高效,有了第三种方式:

public class StaticSingleton {

private StaticSingleton(){

System.out.println("StaticSingleton is create");

}

private static class SingletonHolder {

private static StaticSingleton instance = new StaticSingleton();

}

public static StaticSingleton getInstance() {

return SingletonHolder.instance;

}

} 由于加载一个类时,其内部类不会被加载。这样保证了只有调用getInstance()时才会产生实例,控制了生成实例的时间,实现了延迟加载。

并且去掉了synchronized,让性能更优,用static来确保唯一性。

一个类的内部状态创建后,在整个生命期间都不会发生变化时,就是不变类

不变模式不需要同步

创建一个不变的类:

public final class Product {

// 确保无子类

private final String no;

// 私有属性,不会被其他对象获取

private final String name;

// final保证属性不会被2次赋值

private final double price;

public Product(String no, String name, double price) {

// 在创建对象时,必须指定数据

super();

// 因为创建之后,无法进行修改

this.no = no;

this.name = name;

this.price = price;

}

public String getNo() {

return no;

}

public String getName() {

return name;

}

public double getPrice() {

return price;

}

} Java中不变的模式的案例有:

java.lang.String

java.lang.Boolean

java.lang.Byte

java.lang.Character

java.lang.Double

java.lang.Float

java.lang.Integer

java.lang.Long

java.lang.Short

核心思想是异步调用

非异步:

74da7734ab080db13326d9352cddb7b9.png

异步:

9b4a7b86f27892d7587874ca80f91130.png

第一次的call_return由于任务还没完成,所以返回的是一个空的。

但是这个返回类似于购物中的订单,将来可以根据这个订单来得到一个结果。

所以这个Future模式意思就是,“未来”可以得到,就是指这个订单或者说是契约,“承诺”未来就会给结果。

Future模式简单的实现:

667441527e682de74892b85a29671d0b.png

调用者得到的是一个Data,一开始可能是一个FutureData,因为RealData构建很慢。在未来的某个时间,可以通过FutureData来得到RealData。

代码实现:

public interface Data {

public String getResult ();

}

public class FutureData implements Data {

protected RealData realdata = null; //FutureData是RealData的包装

protected boolean isReady = false;

public synchronized void setRealData(RealData realdata) {

if (isReady) {

return;

}

this.realdata = realdata;

isReady = true;

notifyAll(); //RealData已经被注入,通知getResult()

}

public synchronized String getResult()//会等待RealData构造完成

{

while (!isReady) {

try {

wait(); //一直等待,知道RealData被注入

} catch (InterruptedException e) {

}

}

return realdata.result; //由RealData实现

}

}

public class RealData implements Data {

protected final String result;

public RealData(String para) {

// RealData的构造可能很慢,需要用户等待很久,这里使用sleep模拟

StringBuffer sb = new StringBuffer();

for (int i = 0; i < 10; i++) {

sb.append(para);

try {

// 这里使用sleep,代替一个很慢的操作过程

Thread.sleep(100);

} catch (InterruptedException e) {

}

}

result = sb.toString();

}

public String getResult() {

return result;

}

}

public class Client {

public Data request(final String queryStr) {

final FutureData future = new FutureData();

new Thread() {

public void run()

{

// RealData的构建很慢,

//所以在单独的线程中进行

RealData realdata = new RealData(queryStr);

future.setRealData(realdata);

}

}.start();

return future; // FutureData会被立即返回

}

}

public static void main(String[] args) {

Client client = new Client();

// 这里会立即返回,因为得到的是FutureData而不是RealData

Data data = client.request("name");

System.out.println("请求完毕");

try {

// 这里可以用一个sleep代替了对其他业务逻辑的处理

// 在处理这些业务逻辑的过程中,RealData被创建,从而充分利用了等待时间

Thread.sleep(2000);

} catch (InterruptedException e) {

}

// 使用真实的数据

System.out.println("数据 = " + data.getResult());

} JDK中也有多Future模式的支持:

d6383bc52610249e0aee32d6bafc5b1b.png

接下来使用JDK提供的类和方法来实现刚刚的代码:

import java.util.concurrent.Callable;

public class RealData implements Callable {

private String para;

public RealData(String para) {

this.para = para;

}

@Override

public String call() throws Exception {

StringBuffer sb = new StringBuffer();

for (int i = 0; i < 10; i++) {

sb.append(para);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

}

}

return sb.toString();

}

}

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.FutureTask;

public class FutureMain {

public static void main(String[] args) throws InterruptedException,

ExecutionException {

// 构造FutureTask

FutureTask future = new FutureTask(new RealData("a"));

ExecutorService executor = Executors.newFixedThreadPool(1);

// 执行FutureTask,相当于上例中的 client.request("a") 发送请求

// 在这里开启线程进行RealData的call()执行

executor.submit(future);

System.out.println("请求完毕");

try {

// 这里依然可以做额外的数据操作,这里使用sleep代替其他业务逻辑的处理

Thread.sleep(2000);

} catch (InterruptedException e) {

}

// 相当于data.getResult (),取得call()方法的返回值

// 如果此时call()方法没有执行完成,则依然会等待

System.out.println("数据 = " + future.get());

}

} 这里要注意的是FutureTask是即具有

Future功能又具有Runnable功能的类。所以又可以运行,最后还能get。

当然如果在调用到future.get()时,真实数据还没准备好,仍然会产生阻塞状况,直到数据准备完成。

当然还有更加简便的方式:

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class FutureMain2 {

public static void main(String[] args) throws InterruptedException,

ExecutionException {

ExecutorService executor = Executors.newFixedThreadPool(1);

// 执行FutureTask,相当于上例中的 client.request("a") 发送请求

// 在这里开启线程进行RealData的call()执行

Future future = executor.submit(new RealData("a"));

System.out.println("请求完毕");

try {

// 这里依然可以做额外的数据操作,这里使用sleep代替其他业务逻辑的处理

Thread.sleep(2000);

} catch (InterruptedException e) {

}

// 相当于data.getResult (),取得call()方法的返回值

// 如果此时call()方法没有执行完成,则依然会等待

System.out.println("数据 = " + future.get());

}

} 由于Callable是有返回值的,可以直接返回future对象。

生产者-消费者模式是一个经典的多线程设计模式。它为多线程间的协作提供了良好的解决方案。 在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程。生产者线 程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务。生产者和消费者之间则通 过共享内存缓冲区进行通信。

以前写过一篇用Java来实现生产者消费者的多种方法,这里就不多阐述了。

系列:

[高并发Java 一] 前言

[高并发Java 二] 多线程基础

[高并发Java 三] Java内存模型和线程安全

[高并发Java 四] 无锁

[高并发Java 五] JDK并发包1

[高并发Java 六] JDK并发包2

[高并发Java 七] 并发设计模式

[高并发Java 八] NIO和AIO

[高并发Java 九] 锁的优化和注意事项

[高并发Java 十] JDK8对并发的新支持

转载于:https://my.oschina.net/hosee/blog/614826

[高并发Java 七] 并发设计模式相关教程

[高并发Java 十] JDK8对并发的新支持

[高并发Java 十] JDK8对并发的新支持 为什么80%的码农都做不了架构师? 和AtomicLong类似的使用方式,但是性能比AtomicLong更好。 LongAdder与AtomicLong都是使用了原子操作来提高性能。但是LongAdder在AtomicLong的基础上进行了热点分离,热点分离类似于有锁

JDBC

JDBC 1.JDBC是什么? JDBC(java database connectivity)Java数据库连接。是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。 我们通常说的JDBC是面向关系型数据库的。 2.JDBC访问数据库需要用到的类、

springboot---web---themyleaf语法/java Map

springboot---web---themyleaf语法/java Map 例子 前端显示 你好 java map “键”:值 th语句常用标签 https://blog.csdn.net/qq_35393693/article/details/79653402?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.ch

java BIO和NIO

java BIO和NIO 文章目录 BIO NIO BIO 新建maven项目 mvn archetype:generate -DgroupId=com.it -DartifactId=bio -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=0.0.1-snapshot package com.it;import java.io.IOException; import java.io.In

Java自学路线总结现已收到腾讯Offer。

Java自学路线总结,现已收到腾讯Offer。 本人19本科应届生,专注Java后台学习,已签腾讯WXG的offer。 众所周知,鹅厂后台一直以C++为重,面试官也是做C++开发。但是语言只是工具,对代码的理解才是核心。面试时重点考察的是基础知识,以及解题的思考过程。凭

听说阿里中间件Java面试很难?看看大佬整理的经验吧

听说阿里中间件Java面试很难?看看大佬整理的经验吧 今天为大家整理了一份大佬的阿里中间件面试的面经,希望对大家有帮助,点赞和关注是小编更新的动力哦,废话不多话,正片走起 技术一面考察范围:重点问了Java线程锁:synchronized 和ReentrantLock相关的底

(java)超详细-如何用Eclipse编写第一个Hello World程序

(java)超详细-如何用Eclipse编写第一个Hello World程序 1.eclipse下载 找到eclipse官网(https://www.eclipse.org/downloads/)进行下载合适的版本。(貌似最新的JDK不用配置环境变量能直接使用?) 检查是否可用: 1.WIN+R 输入cmd 回车 2.在黑框框中输入j

JAVA12-String、StringBuffer、StringBuilder的相关知识点

JAVA12-String、StringBuffer、StringBuilder的相关知识点 StringBuffer 是提供一个可变字符串的类 //做了十五次new的过程,String类提供的都是值不能修改的字符串/*String a=1;for (int i = 0; i 15; i++) {a+=i;System.out.println(a.hashCode());}*///Stri

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值