以前學多線程的時候沒有學習線程的同步工具類(輔助類)。ps:當時以爲暫時用不上,認爲是挺高深的知識點就沒去管了..html
在前幾天,朋友發了一篇比較好的Semaphore文章過來,而後在瀏覽博客的時候又發現面試還會考,那仍是挺重要的知識點。因而花了點時間去了解一下。java
Java爲咱們提供了三個同步工具類:面試
這幾個工具類其實說白了就是爲了可以更好控制線程之間的通信問題~編程
- A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
簡單來講:CountDownLatch是一個同步的輔助類,容許一個或多個線程一直等待,直到其它線程完成它們的操做。微信
它經常使用的API其實就兩個:await()
和countDown()
多線程
使用說明:併發
countDown()
使計數器count減1。當count減到0時,全部在等待的線程均會被釋放例子:3y如今去作實習生了,其餘的員工還沒下班,3y很差意思先走,等其餘的員工都走光了,3y再走。ide
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(5);
System.out.println("如今6點下班了.....");
// 3y線程啓動
new Thread(new Runnable() {
@Override
public void run() {
try {
// 這裏調用的是await()不是wait()
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...其餘的5個員工走光了,3y終於能夠走了");
}
}).start();
// 其餘員工線程啓動
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("員工xxxx下班了");
countDownLatch.countDown();
}
}).start();
}
}
}
複製代碼
輸出結果:工具
再寫個例子:3y如今負責倉庫模塊功能,可是能力太差了,寫得很慢,別的員工都須要等3y寫好了才能繼續往下寫。post
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(1);
// 3y線程啓動
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y終於寫完了");
countDownLatch.countDown();
}
}).start();
// 其餘員工線程啓動
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("其餘員工須要等待3y");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y終於寫完了,其餘員工能夠開始了!");
}
}).start();
}
}
}
複製代碼
輸出結果:
參考資料:
- A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.
簡單來講:CyclicBarrier容許一組線程互相等待,直到到達某個公共屏障點。叫作cyclic是由於當全部等待線程都被釋放之後,CyclicBarrier能夠被重用(對比於CountDownLatch是不能重用的)
使用說明:
例子:3y和女友約了去廣州夜上海吃東西,因爲3y和3y女友住的地方不一樣,天然去的路徑也就不同了。因而他倆約定在體育西路地鐵站集合,約定等到相互見面的時候就發一條朋友圈。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) {
new Thread(() -> {
String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女友";
}
System.out.println(name + "到了體育西");
try {
// 兩我的都要到體育西才能發朋友圈
CyclicBarrier.await();
// 他倆到達了體育西,看見了對方發了一條朋友圈:
System.out.println("跟" + name + "去夜上海吃東西~");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
複製代碼
測試結果:
玩了一天之後,各自回到家裏,3y和女友約定各自洗澡完以後再聊天
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) {
new Thread(() -> {
String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女友";
}
System.out.println(name + "到了體育西");
try {
// 兩我的都要到體育西才能發朋友圈
CyclicBarrier.await();
// 他倆到達了體育西,看見了對方發了一條朋友圈:
System.out.println("跟" + name + "去夜上海吃東西~");
// 回家
CyclicBarrier.await();
System.out.println(name + "洗澡");
// 洗澡完以後一塊兒聊天
CyclicBarrier.await();
System.out.println("一塊兒聊天");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
複製代碼
測試結果:
參考資料:
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.
- A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each {@link #acquire} blocks if necessary until a permit is available, and then takes it. Each {@link #release} adds a permit,potentially releasing a blocking acquirer.However, no actual permit objects are used; the {@code Semaphore} just keeps a count of the number available and acts accordingly.
Semaphore(信號量)實際上就是能夠控制同時訪問的線程個數,它維護了一組**"許可證"**。
acquire()
方法時,會消費一個許可證。若是沒有許可證了,會阻塞起來release()
方法時,會添加一個許可證。3y女友開了一間賣酸奶的小店,小店一次只能容納5個顧客挑選購買,超過5個就須要排隊啦~~~
import java.util.concurrent.Semaphore;
public class Test {
public static void main(String[] args) {
// 假設有50個同時來到酸奶店門口
int nums = 50;
// 酸奶店只能容納10我的同時挑選酸奶
Semaphore semaphore = new Semaphore(10);
for (int i = 0; i < nums; i++) {
int finalI = i;
new Thread(() -> {
try {
// 有"號"的才能進酸奶店挑選購買
semaphore.acquire();
System.out.println("顧客" + finalI + "在挑選商品,購買...");
// 假設挑選了xx長時間,購買了
Thread.sleep(1000);
// 歸還一個許可,後邊的就能夠進來購買了
System.out.println("顧客" + finalI + "購買完畢了...");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
複製代碼
輸出結果:
反正每次只能5個客戶同時進酸奶小店購買挑選。
參考資料:
Java爲咱們提供了三個同步工具類:
本文簡單的介紹了一下這三個同步工具類是幹嗎用的,要深刻還得看源碼或者借鑑其餘的資料。
最後補充一下以前的思惟導圖知識點:
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y。
文章的目錄導航: