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语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...
随机推荐
- 新买的orico蓝牙usb连接器使用方法与驱动
因为买的型号是 BTA-403 ,所以需要下载该型号驱动 安装好后,可能会出现找不到蓝牙设备问题,所以需要重启机器,并且手动将pc蓝牙连接到手机蓝牙,然后手机蓝牙再连接蓝牙耳机,此时蓝牙耳机会显示连接 ...
- UWP 卡片视图 Card View
上一篇 提到了 UWP 轨道视图Orbit View,这次就说一下卡片视图,毕竟两个差不多. 卡片视图,效果如其名,卡片一样,左右滑动,当然能翻牌最好了. 嗯,我这个可以的额(⊙﹏⊙)... 看下效果 ...
- jquery选择器:获取父级元素、同级元素、子元素
jQuery的出现给广大开发者提供了不少的方便.从要自己一个一个敲代码,到直接调用方法,无疑大大地提高了网站开发的效率.而在jQuery中有一些方法非常的实用.下面就给大家介绍下jquery选择器:获 ...
- Linux中的mysql指令
如何启动/停止/重启MySQL一.启动方式1.使用 service 启动:service mysqld start2.使用 mysqld 脚本启动:/etc/inint.d/mysqld start3 ...
- nGrinder性能测试平台的安装部署
1.从GitHub下载war包: https://github.com/naver/ngrinder/releases 2.把ngrinder-controller-3.4.2.war重命名为ngri ...
- UnityEditor扩展-Shader浏览器
1. 用途 用于浏览项目所有Shader被使用的情况 2. 界面说明 Ignore Directory:添加不搜索的文件夹,不添加默认搜索全部 Find按钮:开始搜索 Used Shaders:已被使 ...
- 刨根问底KVO原理
介绍 KVO( NSKeyValueObserving )是一种监测对象属性值变化的观察者模式机制.其特点是无需事先修改被观察者代码,利用 runtime 实现运行中修改某一实例达到目的,保证了未侵入 ...
- MAVEN项目导入src/test/java项目报错
转载博客:https://blog.csdn.net/gengjianchun/article/details/78679036 https://blog.csdn.net/jsloveyou/ ...
- 我用Python远程探查室友的网页浏览记录,他不愧是成年人!
过程: 利用Python制作远程查看别人电脑的操作记录,与其它教程类似,都是通过邮件返回. 利用程序得到目标电脑浏览器当中的访问记录,生产一个文本并发送到你自己的邮箱,当然这个整个过程除了你把pyth ...
- GitHub笔记(四)——标签管理
五 标签管理 1 打标签.默认master $ git tag v1.0 要对add merge这次提交打标签,它对应的commit id是f52c633,敲入命令: $ git tag v0.9 f ...