`

java线程安全

    博客分类:
  • java
 
阅读更多

       在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并发实战中,介绍了以下方式安全发布:

  1. 在静态初始化函数中初始化一个对象引用。
  2. 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
  3. 将对象的引用保存到某个正确构造对象的final类。
  4. 将对象的引用保存到一个由锁保护的域中。
  3、线程安全库中的容器提供的安全发布保证:
  1. 通过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,可以安全地将它发布给任何从这些容器中访问它的线程。
  2. 通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或者synchronizedSet中,可以将该元素安全地发布到任何从这些容器中访问该元素的线程。
  3. 通过将某个元素放入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();
  }
}
 
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics