一阅酪、Semaphore
(1)示例
package com.suncy.article.article8;
import lombok.SneakyThrows;
import java.util.concurrent.Semaphore;
public class SyncToolsDemo1 {
public static void main(String[] args) {
//1旨袒、Semaphore并發(fā)數(shù)的限制
//定義了可以訪問資源的線程數(shù)量
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 4; i++) {
int finalI = i;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
//獲取請求許可
semaphore.acquire();
System.out.println(finalI);
Thread.sleep(1000);
//釋放許可
semaphore.release();
}
}).start();
}
}
}
(2)結(jié)果
image.png
(3)結(jié)果說明
打印是先打印0、1遮斥,1秒之后打印2峦失、3。因為設(shè)置的資源并發(fā)訪問數(shù)是2术吗,所以同時只有兩個線程可以訪問資源。
二帆精、CountDownLatch和CyclicBarrier的使用
(1)示例
package com.suncy.article.article8;
import lombok.SneakyThrows;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class SyncToolsDemo2 {
public static void main(String[] args) throws InterruptedException {
//2较屿、調(diào)用await的線程 需要等待countDownLatch為0后才能繼續(xù)執(zhí)行 不可重復(fù)使用
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
int finalI = i + 1;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
Thread.sleep(finalI * 1000);
System.out.println("準(zhǔn)備第" + finalI + "份食材");
countDownLatch.countDown();
}
}).start();
}
// 主線程等待檢查
countDownLatch.await();
System.out.println("食材準(zhǔn)備好了,廚師開始做飯");
//CyclicBarrier 可重復(fù)使用 調(diào)用await的線程阻塞卓练,等待cyclicBarrier為0后繼續(xù)執(zhí)行后續(xù)操作
CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
for (int i = 0; i < 4; i++) {
int finalI = i + 1;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
Thread.sleep(finalI * 1000);
System.out.println("第" + finalI + "個人已經(jīng)到了隘蝎,等待其他人到");
cyclicBarrier.await();
System.out.println("人都到齊了," + finalI + "開始吃飯了");
Thread.sleep(finalI * 1000);
System.out.println("第" + finalI + "吃完飯了,坐到了麻將桌襟企,等待其他人吃完飯");
cyclicBarrier.await();
System.out.println("人都到齊了," + finalI + "開始打麻將");
}
}).start();
}
}
}
(2)結(jié)果
image.png
(3)結(jié)果說明
CountDownLatch一般用于:主線程等待其他線程都執(zhí)行完后嘱么,再進(jìn)行后續(xù)操作。
CyclicBarrier一般用于:其他線程相互等待顽悼,直到達(dá)到了要求的線程數(shù)之后曼振,再進(jìn)行后續(xù)操作。
三蔚龙、Phaser實現(xiàn)CountDownLatch和CyclicBarrier 相同的功能
(1)示例
package com.suncy.article.article8;
import lombok.SneakyThrows;
import java.util.concurrent.Phaser;
public class SyncToolsDemo3 {
public static void main(String[] args) throws InterruptedException {
System.out.println("設(shè)置phase為5");
Phaser phaser = new Phaser(5);
System.out.println("打印初始化之后的phase序列號:" + phaser.getPhase());
System.out.println("打印phaser注冊的值:" + phaser.getRegisteredParties());
for (int i = 0; i < 5; i++) {
final int finalI = i + 1;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
Thread.sleep(finalI * 1000);
System.out.println("第" + finalI + "個線程執(zhí)行任務(wù)");
if (finalI == 5) {
System.out.println("第" + finalI + "個線程執(zhí)行完畢冰评,下次不再參與,此時減少phaser量");
phaser.arriveAndDeregister();
} else {
phaser.arrive();
}
}
}).start();
}
//等待第一輪阻塞的所有節(jié)點都到達(dá)
phaser.awaitAdvance(0);
System.out.println("第1輪同步完之后木羹,打印phase序列號" + phaser.getPhase());
System.out.println("打印phaser注冊的值:" + phaser.getRegisteredParties());
for (int i = 0; i < 4; i++) {
int finalI = i + 1;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
System.out.println("第" + finalI + "個線程正在執(zhí)行任務(wù)");
phaser.arriveAndAwaitAdvance();
}
}).start();
}
phaser.awaitAdvance(1);
System.out.println("第2輪同步完之后甲雅,打印phase序列號" + phaser.getPhase());
System.out.println("給phaser新增一個");
phaser.register();
System.out.println("phaser新增一個之后的值:" + phaser.getRegisteredParties());
for (int i = 0; i < 5; i++) {
int finalI = i + 1;
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
phaser.arriveAndAwaitAdvance();
}
}).start();
}
System.out.println("打印phase序列號:" + phaser.getPhase());
phaser.awaitAdvance(2);
System.out.println("第3輪同步完之后,打印phase序列號" + phaser.getPhase());
}
}
(2)結(jié)果
image.png
(3)結(jié)果說明
getPhase() :拿到周期數(shù)坑填,初始化之后周期數(shù)為0抛人,每輪周期完成之后,會自動加1脐瑰。
arriveAndDeregister():到達(dá)屏障妖枚,并減少屏障數(shù)。
arrive():到達(dá)屏障蚪黑,繼續(xù)執(zhí)行盅惜,不阻塞中剩。
arriveAndAwaitAdvance():到達(dá)屏障,阻塞抒寂,等待其他線程结啼。
register():新增一個屏障。
awaitAdvance(1):根據(jù)周期數(shù)屈芜,判斷當(dāng)前是否需要阻塞郊愧。如果當(dāng)前的周期數(shù)和參數(shù)的值相同,則阻塞等待井佑,否則會繼續(xù)執(zhí)行属铁。
四、Exchanger
(1)示例
package com.suncy.article.article8;
import lombok.SneakyThrows;
import java.util.concurrent.Exchanger;
public class SyncToolsDemo4 {
public static void main(String[] args) throws InterruptedException {
Exchanger<String> exchanger = new Exchanger<String>();
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
String exchange = exchanger.exchange("一瓶飲料");
System.out.println("朋友小花用飲料換到了[" + exchange + "]");
}
}).start();
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
String exchange = exchanger.exchange("2塊錢");
System.out.println("小明用2塊錢換到了[" + exchange + "]");
}
}).start();
}
}
(2)結(jié)果
image.png
(3)結(jié)果說明
用于兩個線程間的數(shù)據(jù)交換躬翁,盡量不要用于多個線程焦蘑,情況不可控。