在开发过程中 当我们拿到一个线程非安全的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类的更多相关文章

  1. 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

  2. 分别应用include指令和include动作标识在一个jsp页面中包含一个文件。

    分别应用include指令和include动作标识在一个jsp页面中包含一个文件. hello.jsp <%@ page language="java" import=&qu ...

  3. Confluence 6 从生产环境中恢复一个测试实例

    请参考 Restoring a Test Instance from Production 页面中的内容获得更多完整的说明. 很多 Confluence 的管理员将会使用生产实例运行完整数据和服务的 ...

  4. JDK中的SimpleDateFormat线程非安全

    在JDK中使用SimpleDateFormat的时候都会遇到线程安全的问题,在JDK文档中也说明了该类是线程非安全的,建议对于每个线程都创建一个SimpleDateFormat对象.如下面一个Case ...

  5. 它可以作为一个代理server或者转发java类

    在项目中使用,这简化和通用汽车.突出的基本思路,细节可以基于此类改变. 基于java容器和servlet. package com.xxx.first; import java.io.Buffered ...

  6. 一接口自动化中生成测试数据需要用到的java类API--import java.util.Properties;

    转载地址:    http://www.cnblogs.com/lay2017/p/8596871.html#undefined 写的很详细

  7. 【多线程补充】SimpleDateFormat非线程安全与线程中、线程组中异常的处理

    1.SimpleDateFormat非线程安全的问题 类SimpleDateFormat主要负责日期的转换与格式化,但在多线程环境中,使用此类容易造成数据转换及处理的不正确,因为SimpleDateF ...

  8. 在多线程环境中使用Jedis

    Jedis是一个Java语言的Redis客户端,它为Java语言连接与操作Redis提供了简单易用的接口. Jedis不是线程安全的.故不应该在多线程环境中共用一个Jedis实例.可是.也应该避免直接 ...

  9. OpenStack环境中的NFV实践

    原文链接:http://www.99cloud.net/html/2016/jiuzhouyuanchuang_1103/250.html 在开始实践之前我们首先需要了解一些NFV概念和术语. NFV ...

随机推荐

  1. 安装MongoDB到CentOS 6

    MongoDB是一个面向海量文档存数据动态存储的NoSQL型数据库.是一个除了用于关系型数据库如MySQL,PostgreSQL数据库表格的格式,和微软SQL以外的一种数据模型存储形式.他的功能包括了 ...

  2. docker删除容器再删除镜像

    1. 查询镜像 docker images 现在想删除第一个,ID为 99f85991949f 的镜像. docker rmi  ID 从上面看出,需要先停到ID为 67*** 的容器. 2. 查询容 ...

  3. Override和Overload的含义与区别

    overload是重载,重载是一种参数多态机制,即代码通过参数的类型或个数不同而实现的多态机制. 是一种静态的绑定机制(在编译时已经知道具体执行的是哪个代码段).  override是重写,重写是一种 ...

  4. C++类的默认成员函数

    成员函数隐含this指针参数: 每成员函数一个隐式的指针形参(构造函数除外): 对象在调用成员函数时,编译器会将对象的地址传递给this指针: 1.构造函数(需用一个公有成员函数对私有的成员变量进行初 ...

  5. JS基础_强制类型转换

    强制类型转换 将一个数据类型强制转换为其他的数据类型 类型转换主要指,将其他数据类型,转换为 string.number.boolean 1.将其他数据类型转换为string(返回值是强转后类型的值) ...

  6. linux系统问题排查

    通常linux系统出问题了 先看系统日志 tail -f /var/log/messages

  7. leetcode-easy-others-461. Hamming Distance

    mycode  92.05% class Solution(object): def hammingDistance(self, x, y): """ :type x: ...

  8. ssh框架中的分页查询

    ssh中的分页查询是比较常用的,接下来我用代码来介绍如何实现一个分页查询 首先建立一个Model用来储存查询分页的信息 package com.haiziwang.qrlogin.utils; imp ...

  9. C++ Vector实践

    实践如下: #include <iostream> #include <vector> #include <typeinfo> using namespace st ...

  10. 操作MySQL出错提示“BLOB/TEXT column request_data in key specification without a key length”解决办法

    错误原因: 查阅资料后才知道,原来Mysql数据库对于BLOB/TEXT这样类型的数据结构只能索引前N个字符.所以这样的数据类型不能作为主键,也不能是UNIQUE的.所以要换成VARCHAR,但是VA ...