1.原子變量(java.util.concurrent.atomic)java
原子狀態,變化不會被打斷,如 AtomicLong , AtomicInteger 緩存
2.內部鎖 synchronized 塊安全
synchronized方法的鎖就是方法所在的對象自己,可重入多線程
3.共享變量併發
Volatile變量,每次從內存取出數據,能夠得到最新的副本。高併發
沒有同步狀況下的共享變量,可能執行順序不是按照代碼的組織,this
public class NoVisibility{ private static boolean ready; private static int number; private static class ReaderThread extends Thread{ public void run(){ while(!ready){ Thread.yield(); } System.out.println(number); } } public static void main(String args[]){ new ReaderThread().start(); number = 42; ready = true; }
棧限制,把本地的引用類型限制在本地線程中,不溢出atom
不可變對象永遠是線程安全的spa
4.ThreadLocal 容許線程和本身的變量保存在一塊兒線程
向已有的線程安全類添加功能,
public class BetterVector<E> extends Vector<E>{ public synchronized boolean putIfAbsent(E x){ ... } }
可是下面這種方式不是線程安全的:
public class ListHelper<E>{ public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x){ ... } }
由於synchronized關鍵字鎖住的是 ListHelpder類,因此並無得到List的鎖,那麼在putIfAbsent中修改List時,是不能保證
其它方法不對list修改。
下面的方法纔是正確的:
public class ListHelper<E>{ public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x){ synchronized(list); ... } }
或者是使用組合實現List接口,這樣第一種方式就是正確的,由於得到了正確的鎖。
5. 同步容器
Java 5.0 提供了併發容器來替換同步容器,提升併發的效率。 ConcurrentHashMap代替SynchronizedMap
FutureTask 經過Callable 實現,能夠理解爲是一個可攜帶結果的Runnable
semaphore 信號量,控制對資源的訪問數量限制
Barrier 提供一種能夠一次執行多個線程,直到全部的線程都完成才繼續進行,有任何一個線程沒有完成,全部
完成的現成都要等待這個線程完成
一個正確的多線程訪問的緩存的寫法
package net.jcip.examples; import java.util.concurrent.*; /** * Memoizer * <p/> * Final implementation of Memoizer * * @author Brian Goetz and Tim Peierls */ public class Memoizer <A, V> implements Computable<A, V> { private final ConcurrentMap<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>(); private final Computable<A, V> c; public Memoizer(Computable<A, V> c) { this.c = c; } public V compute(final A arg) throws InterruptedException { while (true) { Future<V> f = cache.get(arg); if (f == null) { Callable<V> eval = new Callable<V>() { public V call() throws InterruptedException { return c.compute(arg); } }; FutureTask<V> ft = new FutureTask<V>(eval); f = cache.putIfAbsent(arg, ft); if (f == null) { f = ft; ft.run(); } } try { return f.get(); } catch (CancellationException e) { cache.remove(arg, f); } catch (ExecutionException e) { throw LaunderThrowable.launderThrowable(e.getCause()); } } } }