如何在一个线程环境中使用一个线程非安全的java类
在开发过程中 当我们拿到一个线程非安全的java类的时候,我们可以额外创建这个类的管理类 并在管理类中控制同步
比如
一个非线程安全的Pair类
package test.thread.sx.testKuai; /**
* 线程非安全的java类
* 约束条件 两个变量的值必须一致
* @author Administrator
*
*/
public class Pair {
private int x,y;
public Pair(int x,int y){
this.x = x;
this.y = y;
}
public Pair(){
this(0,0);
}
public int getX() {
return x;
} public int getY() {
return y;
}
public void incrementX(){
x++;
}
public void incrementY(){
y++;
}
@Override
public String toString() {
return "Pair [x=" + x + ", y=" + y + "]";
}
public class PairValuesNotEqualException extends RuntimeException { private static final long serialVersionUID = 673137680063170443L; public PairValuesNotEqualException() {
super("Pair value not equal" + Pair.this);
}
}
public void checkState(){
if(x!=y){
throw new PairValuesNotEqualException();
}
} }
那么我们想要在线程安全的环境下来操作这个类的话 我们不可以修改原来类的代码结构 我们可以创建一个新的管理类 为了方便我们使用两种方式来实现同步
所以先创建一个abstract的类 然后在创建这个类的实现类
package test.thread.sx.testKuai; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; public abstract class PairManager {
protected Pair p = new Pair();
protected List<Pair> storge = Collections.synchronizedList(new ArrayList<Pair>()); /**
* 获取pair可以轻松管理同步
* @return
*/
public synchronized Pair getPair(){
return new Pair(p.getX(), p.getY());
}
public abstract void increment(); public void storge(Pair p){ storge.add(p); }
}
然后分别创建两个实现类 一个是直接同步方法 一个同步代码块
同步方法
package test.thread.sx.testKuai;
public class PairManager1 extends PairManager {
@Override
public synchronized void increment() {
p.incrementX();
p.incrementY();
storge(getPair());
}
}
同步代码块
package test.thread.sx.testKuai;
public class PairManger2 extends PairManager {
@Override
public void increment() {
Pair temp;
synchronized (this) {
p.incrementX();
p.incrementY();
temp = getPair();
}
storge(temp);
}
}
其实还可以直接替换 LOCK
package test.thread.sx.testKuai; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class PairManger2 extends PairManager {
private Lock lock = new ReentrantLock(); @Override
public void increment() {
Pair temp;
/* synchronized (this) { */
lock.lock();
p.incrementX();
p.incrementY();
temp = getPair();
lock.unlock();
/* } */
storge(temp);
} }
在保证线程安全的情况下 为了性能最好是尽量减少同步范围
然后创建线程任务 这个是两个变量同时增加的任务
package test.thread.sx.testKuai;
public class PairManipulator implements Runnable {
private PairManager pm ;
public PairManipulator(PairManager pm) {
this.pm = pm;
}
@Override
public void run() {
while(true){
pm.increment();
System.out.println(pm.getPair());
}
}
@Override
public String toString() {
return "pair:" + pm.getPair() ;
}
}
然后创建一个检查任务
package test.thread.sx.testKuai;
public class PairChecker implements Runnable {
private PairManager pm;
public PairChecker(PairManager p) {
pm = p;
}
@Override
public void run() {
while (true) {
/* pm.checkCounter.incrementAndGet();*/
pm.getPair().checkState();
System.out.println(pm.getPair());
}
}
}
然后进行测试
package test.thread.sx.testKuai; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; public class CiiticalSection {
public static void testApproaches(PairManager pmn1,PairManager pmn2){
ExecutorService exc = Executors.newCachedThreadPool();
PairManipulator pm = new PairManipulator(pmn1);
PairManipulator pm2 = new PairManipulator(pmn2);
PairChecker pc = new PairChecker(pmn1);
PairChecker pc2 = new PairChecker(pmn2);
exc.execute(pm);
exc.execute(pm2);
exc.execute(pc);
exc.execute(pc2);
exc.shutdown();
}
public static void main(String[] args) {
PairManager pmn1 = new PairManager1();
PairManager pmn2 = new PairManger2(); testApproaches(pmn1,pmn2); }
}
看下结果
-----------------
Pair [x=159948, y=159948]
Pair [x=159949, y=159949]
Pair [x=159950, y=159950]
--------------------
如何在一个线程环境中使用一个线程非安全的java类的更多相关文章
- 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法
[源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...
- 分别应用include指令和include动作标识在一个jsp页面中包含一个文件。
分别应用include指令和include动作标识在一个jsp页面中包含一个文件. hello.jsp <%@ page language="java" import=&qu ...
- Confluence 6 从生产环境中恢复一个测试实例
请参考 Restoring a Test Instance from Production 页面中的内容获得更多完整的说明. 很多 Confluence 的管理员将会使用生产实例运行完整数据和服务的 ...
- JDK中的SimpleDateFormat线程非安全
在JDK中使用SimpleDateFormat的时候都会遇到线程安全的问题,在JDK文档中也说明了该类是线程非安全的,建议对于每个线程都创建一个SimpleDateFormat对象.如下面一个Case ...
- 它可以作为一个代理server或者转发java类
在项目中使用,这简化和通用汽车.突出的基本思路,细节可以基于此类改变. 基于java容器和servlet. package com.xxx.first; import java.io.Buffered ...
- 一接口自动化中生成测试数据需要用到的java类API--import java.util.Properties;
转载地址: http://www.cnblogs.com/lay2017/p/8596871.html#undefined 写的很详细
- 【多线程补充】SimpleDateFormat非线程安全与线程中、线程组中异常的处理
1.SimpleDateFormat非线程安全的问题 类SimpleDateFormat主要负责日期的转换与格式化,但在多线程环境中,使用此类容易造成数据转换及处理的不正确,因为SimpleDateF ...
- 在多线程环境中使用Jedis
Jedis是一个Java语言的Redis客户端,它为Java语言连接与操作Redis提供了简单易用的接口. Jedis不是线程安全的.故不应该在多线程环境中共用一个Jedis实例.可是.也应该避免直接 ...
- OpenStack环境中的NFV实践
原文链接:http://www.99cloud.net/html/2016/jiuzhouyuanchuang_1103/250.html 在开始实践之前我们首先需要了解一些NFV概念和术语. NFV ...
随机推荐
- python 手动拼接json数据
第一步:分别拼接为字符串 第二步:将字符串转化为list 第三歩:将两个list合并为dict 第四步:将dict转换为接送数据 如: import json keys = ['a', 'b', ' ...
- HDU1176-免费馅饼(DP)
免费馅饼 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- JavaWeb_初识监听器Listener
监听器(listener):对项目起到监听的作用,它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化 监听器是Servlet规范中 ...
- JavaWeb_客户端相对/绝对路径和服务器端路径
客户端的绝对路径和相对路径 相对路径:相对与某个基准目录的路径,在同一根目录下各子目录文件之间的相互引用, 绝对路径:指目录下的绝对位置,直接到的目标位置 @charset "UTF-8&q ...
- 客户端框架-MVVM
MVVM Model-View-ViewModel 如果说MVP是对MVC的进一步改进,那么MVVM则是思想的完全变革.它是将"数据模型数据双向绑定"的思想作为核心,因此在View ...
- [CSP-S模拟测试]:笨小猴(随机化)
题目传送门(内部题118) 输入格式 输入第一行是一个整数$n$,意义如以上所示. 接下来有$2n+1$行,每行为两个正整数,第$i$行的两个正整数分别代表$A_i$和$B_i$. 输出格式 如果无法 ...
- Babel编辑ES6代码
1.安装babel依赖 npm install --save-dev @babel/core @babel/cli @babel/preset-env npm install --save @babe ...
- servlet3.0无web.xml
大家应该都已经知道spring 3.1对无web.xml式基于代码配置的servlet3.0应用.通过spring的api或是网络上高手们的博文,也一定很快就学会并且加到自己的应用中去了.PS:如果还 ...
- 只运行一个loop脚本
#!/bin/bash dir=$(dirname $(readlink -f "$0")) full=$(readlink -f "$0") name=$(b ...
- Mybaits 运行原理流程图