Java并发编程中的设计模式解析(一)
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并发编程中的设计模式解析(一)的更多相关文章
- Java并发编程中的设计模式解析(二)一个单例的七种写法
Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...
- Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- (转)Java并发编程:volatile关键字解析
转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...
- Java并发编程:volatile关键字解析(转载)
转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 ...
- Java并发编程:volatile关键字解析-转
Java并发编程:volatile关键字解析 转自海子:https://www.cnblogs.com/dayanjing/p/9954562.html volatile这个关键字可能很多朋友都听说过 ...
- 6、Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- 转:Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字, ...
- [转载]Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- Java并发编程中的若干核心技术,向高手进阶!
来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...
随机推荐
- 洛咕 P4556 [Vani有约会]雨天的尾巴
终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...
- python面试题(三)
一.项目技术点梳理 (一)Django项目 本项目是用python的Django框架开发的前后端不分离项目.项目采用MVT架构,使用的MySQL和redis数据库,用Django自带的orm与数据库交 ...
- 模拟UNIX(linux)文件系统
操作系统课程设计 一.实验内容 1. 题目:模拟UNIX(linux)文件系统 [问题描述] 在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的 模拟U ...
- 图片轮播,信手拈来(jquery)
制作图片轮播,可以说是js或者jquery学习者应该掌握的技巧.但惭愧的是本菜之前一直一知半解,这回抽了半天多总结了下分享给大家.虽然标题比较吹牛,但目的是希望大家看了之后制作图片轮播会非常迅速. 首 ...
- 【日常训练】Hockey(CodeForces-96C)
题意与分析 对于这题题意的理解比较重要,因为这是一条傻逼题: 大小写保持不变 原串中出现的非法字符串里的每一个字符都要替换 Lucky Letter越多越好 这样一种情况下,算法其实特别简单.我傻逼在 ...
- 基于C#的机器学习--惩罚与奖励-强化学习
强化学习概况 正如在前面所提到的,强化学习是指一种计算机以“试错”的方式进行学习,通过与环境进行交互获得的奖赏指导行为,目标是使程序获得最大的奖赏,强化学习不同于连督学习,区别主要表现在强化信号上,强 ...
- 点斜杠 & 如何查看linux程序安装位置 dpkg -L yyy
方法1: sudo find / -name ssh 方法2: Ubuntu下 看应用程序安装路径的方法 ubuntu下dpkg -L xxx看应用程序安装路径 1.点斜杠 “./”就代表在当前目录下 ...
- mac 上面安装 tree 命令
相信很多使用过Linux的用户都用过tree命令,它可以像windows的文件管理器一样清楚明了的显示目录结构. 但是mac下默认是没有 tree命令的. 1.我们可以使用find命令模拟出tree命 ...
- 微信小程序——音阶练耳 宣传页面
音阶练耳是什么? 音阶练耳小程序是一款听音练习音阶,拥有简介界面的交互式小程序,以虚拟钢琴为辅助乐器,应用于日常练习,涵盖了五个八度内26种调式.以及下行中的所有调式与和声小调式的衍生,提高辨认音阶的 ...
- 冲刺One之站立会议4 /2015-5-17
今天我们继续了昨天未完成的部分,把服务器端的在线人数显示做了出来,但是在调试的时候还有一些不可预知的自己也不会改的bug,让我们有点不知所措,启动时间的显示相对来说比较容易实现. 燃尽图4