我们学习线程安全与同步的知识目的就是要实现一些可复用组件或编写出更大的程序。
java中类是对象抽象,那么怎么实现一个线程安全类是我们必须要知道的并正确使用的技术。
在设计线程安全类的过程中,需要包含以下三个基本元素:
找出构成对象状态的所有变量。
找出约束状态变量的不变性条件。
建立对象状态的并发访问管理策略。
package com.home.thread.thread7; import com.home.thread.safe; public class Counter { /** * @author gaoxu * */ public class SafeThread { private int id = 0; @safe public synchronized int getId(){ if(id==Integer.MAX_VALUE) throw new IllegalStateException("counter overflow"); return ++id; } } }
方法getId被原子化,这里主要是因为id的状态判断是一个约束条件,而这个约束条件决定了id的值的有效性,所以必须对这步操作做原子化处理。
实例封闭
我们在编写程序中多数会使用一些非线程安全的对象来实现数据的存储,这样的对象如果被多线程访问或是写入,那么就必须做线程安全处理,最好的方式是线程中的封闭处理。让我们来看一个经常会用到的实例:
package com.uskytec.ubc.foundation.queue; import java.util.LinkedList; import com.uskytec.ubc.foundation.entity.SmsSubmitEntity; /**保存到短信猫的信息的队列 * @author GaoXu * */ public class LNSentCache { private static LNSentCache instance = null; public synchronized static LNSentCache getInstance() { if (instance == null) instance = new LNSentCache(); return instance; } private final static LinkedList<SmsSubmitEntity> routeCache = new LinkedList<SmsSubmitEntity>(); /** * 添加到指定缓冲池 * @param type * @param smgpConfigID * @param submitMsg * @return */ public synchronized int add(SmsSubmitEntity sms) { routeCache.add(sms); return 1; } /** * 得到指定缓冲池的的对象 * @param sgipConfigID * @return */ public synchronized Object get() { if (routeCache != null&&routeCache.size()>0) return routeCache.removeFirst(); return null; } }
我们利用LinkedList来实现一个先进先出队列,但是LinkedList不是线程安全的,所以我们把它进行实例封闭,这样任何一个线程都可以访问它的值。
线程安全性委托
我们经常会使用ConcurrentHashMap这样的并发对象,它们是java提供的并发变成对象,它们在内部实现了同步机制,所以它们是线程安全的,我们可以把不安全对象Map的访问完全交给它来委托管理,这样通过final类型的处理,我们只需要通过Collections的浅拷贝实现Map的线程安全。
实例我们先不提供,大家可以回去试着写一下,下一节我们在来讨论。
利用现有线程安全的类实现并发添加功能
java api中有很多这样的类,例如:Vector、HashTable等,让我们来看一个例子。
package com.gome.qiantai.tools; import java.util.Vector; import com.gome.qiantai.service.IAppraiseWriterObserverService; /** * @author gaoxu * */ public class ObserverCache { private static ObserverCache instance = null; public synchronized static ObserverCache getInstance() { if (instance == null) instance = new ObserverCache(); return instance; } private static Vector<IAppraiseWriterObserverService> obs = new Vector<IAppraiseWriterObserverService>(); public Vector<IAppraiseWriterObserverService> getObs(){ return obs; } }
我们利用Vector来实现了一个监听器列表的操作。
同步类是我们在实践中经常要实现的类,我们要多思考这样的问题,我的类需要写成线程安全的吗?