1. synchronized
同步鎖,當多個線程爭搶該資源時候,同一時間只容許一個線程拿到.
2. volatile
在讀取改變量值時,讀取的均爲變量的最新值.
3. ThreadLocal
用於在無狀態對象內,每個線程線程獨享的內存空間.常用cookie,connection之類的.
4. InheritableThreadLocal
與ThreadLocal類似,區別是InheritableThreadLocal可以讀取父線程的變量.
5. ReentrantLock
重入鎖,可以多次鎖定與釋放.提供了鎖與釋放鎖的方法,可以實例化的時候,傳入參數指定是否是公平鎖.
重入鎖與同步鎖在線程間通信應用示例:
private static String info = "";
public static void main(String[] args) {
//同步鎖
testSyncLock();
//重入鎖
testReenLock();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//同步鎖
public static void testSyncLock() {
Object lock = new Object();
//線程2讀取info
new Thread(() -> {
synchronized (lock) {
//10秒
try {
long millis = System.currentTimeMillis();
lock.wait(5000);
System.out.println("同步鎖得到的信息:" + info + "消耗時間: " + (System.currentTimeMillis() - millis));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//線程1設置info值,完成之後,通知線程2去取該值
new Thread(() -> {
synchronized (lock) {
info = "同步鎖線程1設置信息....";
//通知線程2,可以向下執行
lock.notifyAll();
}
}).start();
}
//重入鎖
public static void testReenLock() {
ReentrantLock reentrantLock = new ReentrantLock(false);
Condition condition = reentrantLock.newCondition();
//線程2讀取info
new Thread(() -> {
try {
long millis = System.currentTimeMillis();
reentrantLock.lock();
//等待被通知,最多等待5秒
condition.await(10, TimeUnit.SECONDS);
System.out.println("重入鎖得到的信息:" + info + "消耗時間: " + (System.currentTimeMillis() - millis));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//釋放鎖
reentrantLock.unlock();
}
}).start();
//線程1設置info值,完成之後,通知線程2去取該值
new Thread(() -> {
try {
//線程阻塞,等待獲取到鎖
reentrantLock.lock();
//設置info值
info = "重入鎖線程1設置信息....";
//通知
condition.signalAll();
} finally {
//釋放
reentrantLock.unlock();
}
}).start();
}
6.ReentrantReadWriteLock
實現了讀鎖與寫鎖.類似於數據庫的S鎖(共享鎖)與X鎖(獨佔鎖).S鎖與S鎖之間可以共存,與X鎖排斥.對讀取數據加鎖,可以採用S鎖提供併發量.對修改數據,採用X鎖,保證數據的準確性,原子性.
代碼示例:
public static void testRWLock(){
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//讀鎖
ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
readLock.lock();
{
//執行相關讀操作
}
//釋放
readLock.unlock();
//寫鎖
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
{
//執行相關寫操作
}
//釋放
writeLock.unlock();
}
7. ConcurrentHashMap
使用類似於hashMap,但HashMap並不支持併發操作.HashMap在併發下,擴容時候,可能會出現環.因而get的時候,可能會陷入死循環.
在1.8中,ConcurrentHashMap 的性能有了進一步提升,拋棄原有的分塊加鎖機制,改爲對碰撞節點自旋CAS操作,保證原子性.
8. CopyOnWriteArrayList
多線程下的List.在add set,remove 時候,都會加上重入鎖.get時候不加.保證寫入原子性.
9. CopyOnWriteArraySet 同上
10. CountDownLatch
倒計時鎖,在倒計時爲0時候,會發出notifyAll()類似消息.讓wait的線程運行起來.可以用於線程執行計算.
代碼示例:
public static void countDownLatchTest() {
//10個線程執行完成,輸出全部執行完成
CountDownLatch downLatch = new CountDownLatch(10);
long now = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
//每個線程延時300ms
new Thread(() -> {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//執行完成,按下計數器
downLatch.countDown();
}
}).start();
}
try {
//等待線程全部執行完
while (downLatch.getCount() != 0){
Thread.sleep(100);
}
System.out.println("線程全部執行完,耗時:" + (System.currentTimeMillis() - now));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
11. CyclicBarrier
循環等待,CyclicBarrier.await方法,只有當所有線程都處於等待時候,在執行下一步.就像賽馬場,馬匹都有一個門攔着,都ready的時候,纔可以起跑.也可以理解爲田徑場,所有選手跑完比賽,纔可以結束比賽.意義就是全部線程都在await,則自動釋放.與上面一個的區別是,上面一個計數爲0時,開始通知.
示例:
public static void cycTest(){
CyclicBarrier lock = new CyclicBarrier(10) ;
for (int i = 0; i < 10; i++) {
//每個線程延時300ms
int finalI = i;
new Thread(() -> {
try {
lock.await() ;
//這裏線程應該併發
System.out.println("開始起跑" + finalI);
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
try {
//等待500ms
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
12. Semaphore
可以用於線程容積控制,當前可以執行的線程數,就類比於公共廁所,茅坑總數多少,當前多少正在使用,如果都是用,那就需要等待.使用完就釋放.
public static void semaphoreTest() {
//容積3,也就是同事執行的線程只能有3個
Semaphore semaphore = new Semaphore(3) ;
for (int i = 0; i < 10; i++) {
//每個線程延時300ms
int finalI = i;
new Thread(() -> {
try {
//請求資源
semaphore.acquire();
//這裏線程應該併發
System.out.println("開始起跑" + finalI);
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//釋放資源
semaphore.release();
}
}).start();
}
}
13. Ato*類
該類下的操作都是原子性的,調用getAndSet方法,會一直進行cas操作,知道寫入.
單機下的併發操作,目前基本用處很少,現在使用場景基本都是集羣下的併發.集羣下的併發,一般首先需要先處理集羣的併發,可以利用zookeeper,redis,memcache等框架,然後單機下多線程併發處理,才能使用到某些.具體使用場景,可能需要反覆驗證,猜想檢測.