java thread safety

       In java, there are some common sense of thread safe operation, here I will summarize:

       1. The java.util.concurrent.atomic package contains some atomic variable classes for implementing atomic state transitions on values ​​and object references. By replacing the long counter with AtomicLong, all accesses to the counter state are guaranteed to be atomic.

       

@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
   }
}

       At the same time, rationalizing the reasonable size of synchronized code blocks requires a trade-off between various design requirements, including security, simplicity, and performance. Be careful not to mix it with atomic here, because it will bring troubles in operation and management.

//@GuardedBy( lock ) has the following usage forms:

//1, @GuardedBy( "this" ) is protected by the internal lock of the object
//2. @GuardedBy( "fieldName" ) is protected by the lock associated with the fieldName reference.
//3. @GuardedBy( "ClassName.fieldName" ) is preserved by the lock of a static field of a class.
//4. @GuardedBy( "methodName()" ) The lock object is the return value of the methodName() method and is protected by this lock.
//5. @GuardedBy( "ClassName.class" ) is protected by the direct lock object of the ClassName class. rather than a lock object for an instance of this class.

@GuardeBy("this") private long counts;

public synchronized long getCounts(){return counts;}

public void yourMethod()
{
   synchronized(this){
       ++counts;
   }
}

 

  2. Regarding the safe release of mutable objects, in the Java concurrency practice, the following methods of safe release are introduced:

  1. Initialize an object reference in a static initialization function.
  2. Save a reference to an object in a volatile field or an AtomicReference object.
  3. Save a reference to an object to some final class that properly constructs the object.
  4. Save a reference to an object in a field protected by a lock.
  3. The security release guarantee provided by the container in the thread-safe library:
  1. By putting a key or value into a Hashtable, synchronizedMap or ConcurrentMap, it can be safely released to any thread accessing it from these containers.
  2. By placing an element in a Vector, CopyOnWriteArrayList, CopyOnWriteArraySet, synchronizedList, or synchronizedSet, the element can be safely posted to any thread that accesses the element from these containers.
  3. By placing an element into a BlockingQueue or ConcurrentLinkedQueue, the element can be safely posted to any thread that accesses the element from those queues.
  4. Wrong way of using the same lock strategy:
@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;
      }
}
 Correct way:
@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. When using Vector, there will also be abnormal data obtained because the method is not an atomic operation. The solution here is:
public void yourMethod(){
          synchronized(vector){
                //do someThing
                //vector.get(i);
                //vector.put(object);
          }
}
    6. The modification of the container by the iterator does not consider concurrency due to performance reasons. If the data is too large and you do not want to lock the container during iteration, an alternative method is to 'clone' the container and perform it on the copy. Iteration, but during cloning, lock concurrency is considered. 7. Compared with Hashtable and synchronizedMap, ConcurrentHashMap has more advantages and fewer disadvantages, so in most concurrent situations, using ConcurrentHashMap instead of synchronized Map can further improve the scalability of the code. The use of ConcurrentHashMap is abandoned only when the application needs to lock the Map for exclusive access. 8. Use Semaphore to set boundaries for the container, and BlockingQueue can also be used to save the resources of the pool. When the resources are not available, there will be blocking until the useful resources are released.      
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. Coordinate the calculation in the automatic cell derivation system through the CyclicBarrier, which is mainly used to divide a problem into several sub-problems, and assign a sub-thread to each problem. When all the worker threads have completed reaching the barrier, it is necessary to judge whether the next time is required. iterate. Another form is Exchanger, which is a two-party fence, generally used for task judgment and exchange between two buffers.    
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();
  }
}
   

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326072313&siteId=291194637