下面介紹的是JUC包下一些執行緒安全類的一些簡單使用和一些小demo,
Semaphore
信號量,即可以同時使用的執行緒數,tryrequire就是將信號量減一,release就是信號量+1,當等于0就會阻塞,大于零才會喚醒,
當需要控制執行緒訪問數量,可以使用信號量來做控制,比較簡單,
下面是使用信號量改進的資料庫連接池
@Slf4j
public class SemaphoreConnection {
// 連接池物件陣列
private Connection[] connections;
// 使用標記
private AtomicIntegerArray flagArrays;
// 執行緒池大小
private Integer poolSize;
/**
* 信號量
*/
Semaphore semaphore;
public SemaphoreConnection(){
this.poolSize = 5;
connections = new MarkConnection[5];
flagArrays = new AtomicIntegerArray(5);
for (int i = 0; i < connections.length; i++) {
connections[i] = new MarkConnection("連接" + i+1);
}
semaphore = new Semaphore(5);
}
// 連接池的初始化
public SemaphoreConnection(int poolSize) {
this.poolSize = poolSize;
connections = new MarkConnection[poolSize];
flagArrays = new AtomicIntegerArray(poolSize);
for (int i = 0; i < connections.length; i++) {
connections[i] = new MarkConnection("連接" + i);
}
semaphore = new Semaphore(poolSize);
}
// 向連接池中請求連接
public Connection getConnection(){
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true){
for (int i = 0; i < poolSize; i++) {
// 進行cas請求,如果請求失敗就失敗
if (flagArrays.compareAndSet(i,0,1)){
return connections[i];
}
}
}
}
/**
* 釋放連接
* @param con
*/
public void releaseConnection(Connection con){
for (int i = 0; i < poolSize; i++) {
if (con == connections[i]){
// 將連接標識置為0即空間連接
flagArrays.set(i,0);
semaphore.release();
}
}
}
public static void main(String[] args) {
SemaphoreConnection myConnectionPoll = new SemaphoreConnection(3);
for (int i = 0; i < 10; i++) {
new Thread(() ->{
MarkConnection connection =(MarkConnection) myConnectionPoll.getConnection();
log.debug("獲得鎖{}",connection.getConName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myConnectionPoll.releaseConnection(connection);
log.debug("釋放鎖{}",connection.getConName());
}).start();
}
}
}
CountDownLatch
就是一個用來計數的,來解決執行緒之間通信的問題,
比如我需要兩個執行緒執行完畢后再去執行主執行緒,我們可以用join方法,但是我們同樣可以使用這個類來控制,
通過一個count,當其被減為0時,呼叫await阻塞的執行緒就會喚醒,
// 一個簡單的demo
@Slf4j
public class Test2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
// for(int i = 0;i < 3;i++){
new Thread(()->{
log.debug("來啦");
try {
Thread.sleep(1000);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("干啦兄弟們");
}).start();
new Thread(()->{
log.debug("來啦");
try {
Thread.sleep(2000);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("干啦兄弟們");
}).start();
// }
countDownLatch.await();
log.debug("開吃了兄弟們");
}
}
同時可以作為微服務下的多執行緒呼叫,當我們需要多個微服務的結果時,我們可以使用多執行緒,呼叫多執行緒池使用多執行緒的方法遠程呼叫,可以使用該類控制主執行緒等待執行緒池中的執行緒執行完后執行主執行緒,但是使用Future可以解決問題,所以還是建議使用future,使用callable方法,
CyclicBarrier
作為一個和CountDownLatch功能相似,但是它卻是可以回圈使用的,當其置為0時,喚醒執行緒后,就會恢復到初始值,可以繼續使用,而CountDownLatch卻是一次性的,需要重復創建執行緒,
CyclicBarrier主要是呼叫一個await方法,等待其他執行緒,當到達數量的執行緒完成后,就會喚醒被await方法阻塞的執行緒,
// demo
@Slf4j
public class Test3 {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(()->{
log.debug("來啦");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("干啦兄弟們");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
log.debug("來啦");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("干啦兄弟們");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
log.debug("來了啊");
}
}
ConcurrentHashMap
保證了多執行緒下hashmap的安全,
jdk1.7時會產生死鏈,因為jdk1.7時多執行緒下是在鏈表頭往里面加,而 不是1.8在鏈表尾加,所以會出現多執行緒下鏈表出現環,無法結束程式,
Concurrent類在多執行緒下的表現為
- 內部使用cas進行優化,可以支持較大的吞吐量
- 弱一致性
- 迭代時的弱一致性,當在迭代是被更新,迭代不會報錯但是會表現出舊值
- size的弱一致性,會讀到舊值
- 讀取一致性
fast-fail快速失敗就是當其他執行緒修改了,非安全容器就會讓正在遍歷的直接拋出例外,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/477506.html
標籤:Java
上一篇:Spring Ioc原始碼分析系列--Ioc容器注冊BeanPostProcessor后置處理器以及事件訊息處理
下一篇:Java 15 新特性:隱藏類
