在java中,有一些线程安全操作的常识,在这里我进行总结一下:
1、java.util.concurrent.atomic包中包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。通过用AtomicLong来代替long类型的计数器,能够确保所有对计数器状态的访问操作都是原子的。
@ThreadSafe
public class Counting{
private final AtomicLong count = new AtomicLong(0);
public long getCount(){
return count.get();
}
//safe method
public yourMathod(){
//do something
count.incrementAndGet();
//do something
}
}
同时合理利用同步代码块的合理大小,需要在各种设计需求中间进行权衡,包括安全性、简单性和性能。注意这里不要和atomic进行混用,因为这样会带来操作和管理上的麻烦。
//@GuardedBy( lock )有以下几种使用形式:
//1、@GuardedBy( "this" ) 受对象内部锁保护
//2、@GuardedBy( "fieldName" ) 受 与fieldName引用相关联的锁 保护。
//3、@GuardedBy( "ClassName.fieldName" ) 受 一个类的静态field的锁 保存。
//4、@GuardedBy( "methodName()" ) 锁对象是 methodName() 方法的返值,受这个锁保护。
//5、@GuardedBy( "ClassName.class" ) 受 ClassName类的直接锁对象保护。而不是这个类的某个实例的锁对象。
@GuardeBy("this") private long counts;
public synchronized long getCounts(){return counts;}
public void yourMethod()
{
synchronized(this){
++counts;
}
}
2、关于可变对象的安全发布,在Java并发实战中,介绍了以下方式安全发布:
- 在静态初始化函数中初始化一个对象引用。
- 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
- 将对象的引用保存到某个正确构造对象的final类。
- 将对象的引用保存到一个由锁保护的域中。
3、线程安全库中的容器提供的安全发布保证:
- 通过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,可以安全地将它发布给任何从这些容器中访问它的线程。
- 通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或者synchronizedSet中,可以将该元素安全地发布到任何从这些容器中访问该元素的线程。
- 通过将某个元素放入BlockingQueue或者ConcurrentLinkedQueue中,可以将该元素安全地发布到任何从这些队列中访问该元素的线程。
4、使用同一个锁策略
错误方式:
@NotThreadSafe
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
}
return absent;
}
}
正确方式:
@NotThreadSafe
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x){
synchronized(list){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
}
return absent;
}
}
}
5、在使用Vector时也会出现由于方法不是原子操作,导致得到的数据异常,这里的解决办法是:
public void yourMethod(){
synchronized(vector){
//do someThing
//vector.get(i);
//vector.put(object);
}
}
6、迭代器对容器的修改由于性能的原因是没有考虑并发的,如果数据过于太大,不希望在迭代期间对容器加锁,那么一种替代方法就是‘克隆’容器,并在副本上进行迭代,但是在克隆的期间,是会考虑加锁并发的。
7、与Hashtable和synchronizedMap相比,ConcurrenctHashMap有着更多的优势以及更少的劣势,因此在大多数并发情况下,用ConcurrentHashMap来代替同步Map能进一步提高代码的可伸缩性。只有当应用程序需要加锁Map以进行独占访问时,才放弃使用ConcurrentHashMap。
8.使用Semaphore为容器设置边界,也可以用BlockingQueue来保存池的资源,当资源没有时,会出现阻塞,直到有用资源的释放。
public class BoundedHashSet<T>{
private final Set<T> set;
private final Semaphore sem;
public BoundedHashSet(int bound){
this.set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException{
sem.acquire();
boolean wasAdded = false;
try{
wasAdded = set.add(o);
return wasAdded;
}
finally{
if(!wasAdded)
sem.release();
}
}
public boolean remove(Object o){
boolean wasRemoved = set.remove(o);
if(wasRemoved){
sem.release();
}
return wasRemoved;
}
}
9.通过CyclicBarrier协调细胞自动衍生系统中的计算,主要用于把一个问题分成几个子问题,并每个问题分配一个子线程,当所有工作线程都完成到达栅栏时,来判断是否需要进行下一次迭代。另外一种形式是Exchanger,他是两方(Two-party)栅栏,一般用于两个缓冲区进行任务判断交换。
public class CellularAutomata{
private final Board mainBoard;
private final CyclicBarrier barrier;
private final Worker[] workers;
public CellularAutomata(Board board){
this.mainBoard = board;
int count = Runtime.getRuntime().availableProcessors();
this.barrier = new CyclicBarrier(count,new Runable(){
public void run(){
mainBoard.commitNewValues();
}
});
this.workers = new Worker[count];
for(int i=0;i<count;i++){
workers[i] = new Worker(mainBoard.getSubBoard(count,i));
}
}
private class Worker implements Runnable{
private final Board board;
public Worker(Board board){this.board = board;}
public void run(){
while(!board.hasConverged()){
for(int x=0;x < board.getMaxX();x++){
for(int y=0;y<board.getMaxY();y++)
board.setNewValue(x,y,computeValue(x,y));
}
try{
barrier.await();
} catch(InterruptedException ex){
return;
} catch(BrokerBarrierException ex){
return;
}
}
}
}
public void start(){
for(int i=0;i<workers.lengthl;i++)
new Thread(workers[i]).start();
mainBoard.waitForConvergence();
}
}
分享到:
相关推荐
java线程安全总结.doc。。。。。。。。
java 线程安全的几个测试小例子,充分的理解JMM中的线程内存模型
其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...
Java线程安全
JAVA线程安全及性能的优化.doc
用思维导图将Java线程安全性相关基本概念联系起来
我认为要认识java线程安全,必须了解两个主要的点:java的内存模型,java的线程同步机制。特别是内存模型,java的线程同步机制很大程度上都是基于内存模型而设定的。后面我还会写java并发包的文章,详细总结如何利用...
该资源包含了一个java线程安全以及生产者消费者demo,可以参考博客:
Java线程安全.pdf
java线程安全总结,是经过多人的经验总结出来的
java线程安全总结.pdf
java线程安全性精讲
Java 线程安全 与 锁.doc
Java线程安全[借鉴].pdf