Callable接口和JUC輔助類

Callable接口:

回顧:

創建線程的四種方式:

  1. 繼承Thread
  2. 實現runnable接口
  3. 實現callable接口
  4. 使用線程池

之前的文章:多線程編程1-定義理解與三種實現方式

Runnable和Callable接口的差异:

  1. Runnable無返回值,Callable有返回值
  2. Runnable不拋异常,Callable拋异常
  3. 實現名稱不同,Runnable是run方法,Callable是call方法
class MyThread1 implements Runnable{
@Override
public void run() { }
} class MyThread2 implements Callable{ @Override
public Integer call() throws Exception {
return 200;
}
}

Runnable 接口實現類FutureTask

FutureTask構造可以傳遞callable

這是類的繼承結構:

別名:可取消的异步,簡單的理解是當主線程中存在耗時高的任務時,可以單開一個子線程處理,主線程處理耗時少的任務,最終匯合在一起。

需要注意的是,使用FutureTask當得到第一次結果後,第二次獲取時直接返回結果,也可以說所有的任務只匯總一次。

JUC輔助類:

CountDownLatch(减少計數)

定義:一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。用給定的計數 初始化 CountDownLatch。由於調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之後,會釋放所有等待的線程,await 的所有後續調用都將立即返回。這種現象只出現一次——計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier

CountDownLatch 是一個通用同步工具,它有很多用途。將計數 1 初始化的 CountDownLatch 用作一個簡單的開/關鎖存器,或入口:在通過調用 countDown() 的線程打開入口前,所有調用 await 的線程都一直在入口處等待。用 N 初始化的 CountDownLatch 可以使一個線程在 N 個線程完成某項操作之前一直等待,或者使其在某項操作完成 N 次之前一直等待

/**
* 問題,當六個人走出教室,則班長鎖門
*/
public class CountDownLatch07 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(6);
for(int i = 1; i <= 6; i++){
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+" 號同學走出教室");
latch.countDown();
},String.valueOf(i)).start();
}
latch.await();
System.out.println(Thread.currentThread().getName()+"班長鎖門");
}
}

其使用的方法,CountDownLatch latch = new CountDownLatch(6)、latch.countDown()、latch.await();

CyclicBarrier(循環栅欄)也可以實現CountDownLatch效果,CyclicBarrier在所有線程執行完畢之後是可以重用的。

CyclicBarrier(循環栅欄)

源碼定義:

一種同步輔助工具,它允許一組線程全部等待彼此到達公共屏障點。 CyclicBarriers 在涉及固定大小的線程組的程序中很有用,這些線程必須偶爾相互等待。 屏障被稱為循環的,因為它可以在等待線程被釋放後重新使用。

簡單的理解,當達到設置的要求後,執行特定的內容,相當於監聽器;

實例代碼:

public class JucUtils {
private static final Integer NUMBER = 7;
public static void main(String[] args) {
//設置資源要求,達到後所需要執行的任務
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("資源達到要求!");
});
//對設置的目標前進
for (int i = 1; i <= 7; i++) {
int finalI = i;
new Thread(()->{
try {
System.out.println("資源正在收集:"+ Thread.currentThread().getName());
//等待,當等待的線程數量到達設置的值,調用執行任務並釋放這些線程。
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}

感興趣的可以看看源碼:

-------------------------CyclicBarrier--------------------
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties; //設置臨界值
this.barrierCommand = barrierAction;
}
----------------------------await-----------------------
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//------------------dowait部分代碼-------------------
final Generation g = generation; if (g.broken)
throw new BrokenBarrierException(); if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
} int index = --count; //每次等待,所需資源-1;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
} //------nextGeneration----------
private void nextGeneration() {
// signal completion of last generation
trip.signalAll(); //喚醒線程
// set up next generation
count = parties;
generation = new Generation();
}

Semaphore(信號燈)

如果對操作系統有所了解的話,該工具類就是信號量+pv操作的集合,對信號量的操作只有三種,初始化、p操作、v操作,其中信號量就是Semaphore初始化的(某種資源的數量),p操作對應的是semaphore.acquire(),信號量--,v操作對應的semaphore.release(),信號量++,當Semaphore初始化唯1時,則為互斥資源。

package com.JUC;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; /**
* 類比操作系統的中信號量PV操作
*/
public class Semaphore07 {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for(int i = 1; i <= 6; i++){
new Thread(()->{
try {
semaphore.acquire(); //加鎖
System.out.println(Thread.currentThread().getName()+" 搶到了車比特");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));//隨機時間停車
System.out.println(Thread.currentThread().getName()+"-------離開了車比特"); } catch (InterruptedException e) {
e.printStackTrace();
}finally{
semaphore.release(); //解鎖
}
},String.valueOf(i)).start();
}
}
}

JUC之Callable接口回顧和JUC輔助類的更多相關文章

  1. 基於接口回調詳解JUC中Callable和FutureTask實現原理

    Callable接口和FutureTask實現類,是JUC(Java Util Concurrent)包中很重要的兩個技術實現,它們使獲取多線程運行結果成為可能.它們底層的實現,就是基於接口回調技術. ...

  2. JUC之Lock接口以及Synchronized回顧

    Lock接口 Synchronized關鍵字回顧: 多線程編程步驟(上): 創建資源類,在資源類創建屬性和操作方法 創建多個線程,調用資源類的操作方法 創建線程的四種方式: 繼承Thread 實現Ru ...

  3. JUC—Callable接口

    一.callable接口是什麼? 面試題: 獲得多線程的方法幾種? 正確答案如下: 傳統的 是繼承thread類和實現runnable接口, java5以後又有實現 callable接口 和 java ...

  4. 實現多線程的方式之實現Callable接口

    package com.hls.juc; import java.util.concurrent.Callable;import java.util.concurrent.ExecutionExcep ...

  5. 實現Callable接口創建線程

    創建執行線程有四種方式: 實現implements接口創建線程 繼承Thread類創建線程 實現Callable接口,通過FutureTask包裝器來創建線程 使用線程池創建線程 下面介紹通過實現Ca ...

  6. 創建執行線程方式三:實現Callable接口

    Callable接口 ① Java 5.0 在 java.util.concurrent 提供了一個新的創建執行 線程的方式:Callable 接口② Callable 接口類似於 Runnable, ...

  7. Callable接口、Runable接口、Future接口

    1. Callable與Runable區別 Java從發布的第一個版本開始就可以很方便地編寫多線程的應用程序,並在設計中引入异步處理.Thread類.Runnable接口和Java內存管理模型使得多線 ...

  8. 線程池的應用及Callable接口的使用

    public interface Executor { /** * Executes the given command at some time in the future.  The comman ...

  9. [改善Java代碼]异步運算考慮使用Callable接口

    多線程有兩種實現方式: 一種是實現Runnable接口,另一種是繼承Thread類,這兩種方式都有缺點,run方法沒有返回值,不能拋出异常(這兩個缺點歸根到底是Runable接口的缺陷,Thread也 ...

  10. 多線程——實現Callable接口

    前兩篇博客(多線程--繼承Thread類.多線程--實現Runnable接口 )介紹了java使用線程的兩種方法.這篇博客繼續介紹第三種方法--實現Callable接口. 先說一下Runnable和C ...

隨機推薦

  1. PHP--獲取響應頭(Response Header)方法

    方法一: $baiduUrl = "http://www.baidu.com/link";   file_get_contents($baiduUrl); $responseInf ...

  2. RT-Thread信號量實際運用—按鍵點燈

    上面是魔笛開發板上 LED 和按鍵的 IO 分布,我們通過信號量的方法來同步按鍵線程和LED 線程,實現當 enter 鍵按下後,點亮或關閉 LED 的動作. /******************* ...

  3. 關於sql語句in的使用注意規則( 轉)

    select * from tuser where userno not in(select userno from filter_barcode) 上面這條語句子查詢裏,userno 並不存在fil ...

  4. 基於Vue2寫的一個有關美食項目

    剛學Vue練習的一個項目 使用Vue2+vue-router+vuex+axios+webpack router使用了默認的hash模式 引入了高德地圖和element-ui 項目地址點擊這裏 演示地 ...

  5. 圖論算法之DFS與BFS

    概述(總) DFS是算法中圖論部分中最基本的算法之一.對於算法入門者而言,這是一個必須掌握的基本算法.它的算法思想可以運用在很多地方,利用它可以解决很多實際問題,但是深入掌握其原理是我們靈活運用它的關 ...

  6. Android 讀寫權限,已經授權情况下,仍然(Permission denied)

    首次安裝APP,獲取讀寫權限以後, 當讀取文件時候,仍然會遇見(Permission denied)錯誤,解决方案是殺掉APP,重新打開APP即可. 應該屬於部分版本系統的bug,直到APP所有的pr ...

  7. wav文件格式分析與詳解

    WAV文件是在PC機平臺上很常見的.最經典的多媒體音頻文件,最早於1991年8月出現在Windows 3.1操作系統上,文件擴展名為WAV,是WaveFom的簡寫,也稱為波形文件,可直接存儲聲音波形, ...

  8. mysql 數據庫關於增加用戶權限的問題

    一新建用戶 ----------- 二首先修改權限必須在電腦cmd 中運行 開設的權限  主要就是 1 所有庫的  *.*      2  所有的錶   db.*      3所有的字段db.t1   ...

  9. 使用jackson美化輸出json/xml

    轉載:http://www.cnblogs.com/xiwang/ 如何使用jackson美化輸出json/xml 1.美化POJO序列化xml 下面將POJO列化為xml並打印. Person pe ...

  10. 讀取.properties配置文件並保存到另一個.properties文件內

    代碼如下 import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileOutputSt ...