Java并发编程,除了被用于各种Web应用、分布式系统和大数据系统,构成高并发系统的核心基础外,其本身也蕴含着大量的设计模式思想在里面。这一系列文章主要是结合Java源码,对并发编程中使用到的、实现的各类设计模式做归纳总结,以便进一步沉淀对Java并发设计的理解。

模板设计模式

Thread类中run和start方法,就是一个典型的模板设计模式的实现,即:父类定义算法逻辑代码,子类实现其细节

 public synchronized void start() {
/**
* 线程对象新建后的New状态,其内部thereadStatus属性为0
*/
if (threadStatus != 0)
throw new IllegalThreadStateException(); /* 同时会被添加到一个ThreadGroup */
group.add(this); boolean started = false;
//调用JNI方法start0()来启动线程
try {
start0();
started = true;
} finally {
//线程结束之后,再次启动将抛出异常
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}

下面以一个例子演示模板模式:

public class TemplateMethod {
//相当于Thread类的start方法, 用final修饰避免被更改
public final void print(String message) {
System.out.println("-------------");
wrapPrint(message);
System.out.println("-------------");
}
//相当于Thread的run方法, 用protected修饰限于子类重写
protected void wrapPrint(String message) { } public static void main(String[] args) {
//通过匿名内部子类, 重写父类的wrapPrint方法, 从而实现不同的输出模板
TemplateMethod t1 = new TemplateMethod() {
@Override
protected void wrapPrint(String message) {
System.out.println("111" + message + "111");
}
};
t1.print("Hello World!"); TemplateMethod t2 = new TemplateMethod() {
@Override
protected void wrapPrint(String message) {
System.out.println("222" + message + "222");
}
};
t2.print("Hello World!");
}
}

策略模式

创建Java多线程中,实现Runnable接口作为Target并传入Thread类的构造方法来生成线程对象的过程,就体现了GoF中策略模式的设计思想。下面是一个简单的示例:

首先,仿照Runnable接口的思想,定义一个用于处理数据库行的接口

 /*
* RowHandler定义了对数据库查询返回结果操作的方法, 具体实现需要
* 实现类完成, 类似于Runnable接口
*/
public interface RowHandler<T> {
T handle(ResultSet rs);
}

然后,仿照Thread方法,定义数据库查询的工作类

 public class RecordQuery  {

     private final Connection connection;

     public RecordQuery(Connection connection) {
this.connection = connection;
}
//方法中传入RowHandler的实现类
public <T> T query(RowHandler<T> handler, String sql, Object... params) throws SQLException {
PreparedStatement stmt;
ResultSet resultSet;
stmt = connection.prepareStatement(sql);
int index = 1;
for (Object param : params) {
stmt.setObject(index++, param);
}
resultSet = stmt.executeQuery();
//调用实现类的handle方法来处理数据
return handler.handle(resultSet);
}
}

生产者-消费者模式

生产者-消费者模式是使用Java并发编程通信所实现的经典模式之一。该模式是通过队列这一数据结构来存储对象元素,由多线程分别充当生产者和消费者,生产者不断生成元素、消费者不断消费元素的过程。下面通过代码来演示:

实现一个带有入队和出队的队列

 /*
* 通过一个生产者-消费者队列来说明线程通信的基本使用方法
*/
public class EventQueue {
//定义一个队列元素数量, 一旦赋值则不可更改
private final int max;
//定义一个空的内部类, 代表存储元素
static class Event{ }
//定义一个不可改的链表集合, 作为队列载体
private final LinkedList<Event> eventQueue = new LinkedList<>();
//如果不指定初始容量, 则容量默认为10
private final static int DEFAULT_MAX_EVENT = 10;
//使用自定义容量初始化队列
public EventQueue(int max) {
this.max = max;
}
//如果不指定初始容量, 则容量默认为10
public EventQueue() {
this(DEFAULT_MAX_EVENT);
}
//封装一个输出到控制台的方法
private void console(String message) {
System.out.printf("%s:%s\n",Thread.currentThread().getName(), message);
}
//定义入队方法
public void offer(Event event) {
//使用链表对象作为锁, 通过synchronized代码块实现同步
synchronized(eventQueue) {
//在循环中判断如果队列已满, 则调用锁的wait方法, 使生产者线程阻塞
while(eventQueue.size() >= max) {
try {
console(" the queue is full");
eventQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
console(" the new event is submitted");
eventQueue.addLast(event);
//唤醒所有等待中的消费者;注意如果此处使用notify(),可能导致线程不安全
this.eventQueue.notifyAll();
}
}
//定义出队方法
public Event take() {
//使用链表对象作为锁
synchronized(eventQueue) {
//在循环中判断如果队列已空, 则调用锁的wait方法, 使消费者线程阻塞
while(eventQueue.isEmpty()) {
try {
console(" the queue is empty.");
eventQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Event event = eventQueue.removeFirst();
//唤醒所有等待中的生产者;注意如果此处使用notify(),可能导致线程不安全
this.eventQueue.notifyAll();
console(" the event " + event + " is handled/taked.");
return event;
}
}
}

验证该队列的类

 /*
* producer/client pattern
*/
public class EventClient { public static void main(String[] args) {
//定义不可变队列实例
final EventQueue eventQueue = new EventQueue();
//新建生产者线程, 可以设置多个
new Thread(()->{
while(true) {
eventQueue.offer(new EventQueue.Event());
}
}, "producer").start();
//新建消费者线程, 可以设置多个
new Thread(()->{
while(true) {
eventQueue.take();
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "consumer").start();
}
}

Java并发编程中的设计模式解析(一)的更多相关文章

  1. Java并发编程中的设计模式解析(二)一个单例的七种写法

    Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...

  2. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  3. (转)Java并发编程:volatile关键字解析

    转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...

  4. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析   Java并发编程:volatile关键字解析 ...

  5. Java并发编程:volatile关键字解析-转

    Java并发编程:volatile关键字解析 转自海子:https://www.cnblogs.com/dayanjing/p/9954562.html volatile这个关键字可能很多朋友都听说过 ...

  6. 6、Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  7. 转:Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字, ...

  8. [转载]Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  9. Java并发编程中的若干核心技术,向高手进阶!

    来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...

随机推荐

  1. [FJOI2015]火星商店问题

    [FJOI2015]火星商店问题 神仙线段树分治...不过我不会. 这题用线段树套可持久化Trie还是能写的. 常数有点大,洛谷垫底水平. // luogu-judger-enable-o2 #inc ...

  2. python json.dumps中文乱码

    json.dumps在默认情况下,对于非ascii字符生成的是相对应的字符编码,而非原始字符,例如: >>> import json>>> js = json.lo ...

  3. 菜鸟vimer成长记——第4.1章、通用插件

    简介 关于插件的分类,此系列只会简单的区分为通用插件和编程插件.通用插件的意思是,不基于任何编程语言都可以使用的插件.编程插件,是针对于编程习惯,或者说是针对于某种语言的插件. 计划中,是先把基本常用 ...

  4. 使用Sublime Text 3作为React Native的开发IDE

    1.下载安装Sublime 3 Sublime 3的下载地址:http://www.sublimetext.com/3 选相应的平台进行下载,安装. 2.安装Package Control 默认的Su ...

  5. python爬取快手ios端首页热门视频

    最近快手这种小视频app,特别的火,中午吃过午饭,闲来无聊,想搞下快手的短视频,看能不能搞到. 于是乎, 打开了fiddler,开始准备抓包, 设置代理,重启,下一步,查看本机ip 手机打开网络设置 ...

  6. javaweb学习1——加密

    声明:本文只是自学过程中,记录自己不会的知识点的摘要,如果想详细学习JavaWeb,请到孤傲苍狼博客学习,JavaWeb学习点此跳转 本文链接:https://www.cnblogs.com/xdp- ...

  7. Java中的Union Types和Intersection Types

    前言 Union Type和Intersection Type都是将多个类型结合起来的一个等价的"类型",它们并非是实际存在的类型. Union Type Union type(联 ...

  8. tomcat9在centos7上启动慢问题

    /opt/java/jdk1.8.0_162/jre/lib/security/java.security 将如下配置securerandom.source=file:/dev/random 改为se ...

  9. [linux] 查看网卡UUID

    virtualbox复制了虚拟机,重新初始化网卡后,需要对/etc/sysconfig/network-scripts/ifcfg-eth0更新UUID值,虽然不改暂时也没发现有问题. 网上查找需要n ...

  10. linux后退文件夹命令

    后退文件夹: cd -  在重复一遍就是前进了