1. 程式人生 > >用Callable實現在走完10個執行緒之後再進行操作

用Callable實現在走完10個執行緒之後再進行操作

昨天一個碰到了一個題目:

如何程式設計,使得主執行緒在跑完十個執行緒之後,再進行後續操作。

看到這個問題,我的第一反應就是可以使用Callable來實現。因為實現執行緒有兩種方式,實現Callable介面或者實現Runnable介面(至於繼承Thread類,我覺得這個方式其實本質上還是實現了Runnable介面)。但是用Runnable實現執行緒,我們一般是不知道執行緒有沒有跑完的,除非經過特殊處理(如使用CountDownLatch)(ps:使用執行緒池的submit()可以返回一個future,呼叫其isDone()方法也可以確認其是否完成,2018-05-08修改)。但是如果使用Callable實現執行緒,我們是可以在call()方法中返回一個值,來確認此執行緒跑完了。因此,我們可以在主執行緒中收集Callable的返回值,直到收集滿了十個以後,再進行後續操作,沒有收集滿的話,就讓主執行緒先休眠一會兒(這個只是初步想法,後續可以優化)。

現在,我們使用Callable來實現這個目的。

class MyCallable implements Callable<Integer>{
	private static int count = 0;
	private static Random random = new Random();
	private final int id = count ++;
	public Integer call() throws Exception {
		System.out.println("執行緒 \t" + id +"\t開始了");
		//模擬工作耗時
		int time = random.nextInt(3) + 1 ;
		System.out.println("執行緒 \t" + id +"\t耗時" + time + "秒");
		Thread.sleep(1000 * time);
		return id;
	}
}
/**
 * 2018-05-04
 * @author liujie
 *
 */
public class TestCallable {
	public static void main(String[] args) throws Exception{
		int SIZE = 10;
		int finished = 0;
		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
		//我們使用一個List來存放Callable的返回值
		List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
		for (int i = 0; i < SIZE; i++) {
			Thread.sleep(100);
			futures.add(cachedThreadPool.submit(new MyCallable()));
		}
		while (finished < SIZE) {
			for (Future<Integer> future : futures) {
				Integer id = future.get();
				System.out.println("主執行緒收集的到了 \t" + id + "\t執行緒的返回值");
				finished ++ ;
			}
		}
		System.out.println(SIZE + "\t個執行緒都跑完了,繼續主執行緒的工作");
	}
}

如程式碼所示,我們在主執行緒中每隔0.1秒開啟一個執行緒,一共開啟十個,使用一個List收集callable的返回值,知道收集十個返回值為止。

控制檯列印情況如下:

執行緒 	0	耗時1秒
執行緒 	1	耗時1秒
執行緒 	2	耗時3秒
執行緒 	3	耗時1秒
執行緒 	4	耗時1秒
執行緒 	5	耗時3秒
執行緒 	6	耗時3秒
執行緒 	7	耗時2秒
執行緒 	8	耗時1秒
執行緒 	9	耗時3秒
主執行緒收集的到了 	0	執行緒的返回值
主執行緒收集的到了 	1	執行緒的返回值
主執行緒收集的到了 	2	執行緒的返回值
主執行緒收集的到了 	3	執行緒的返回值
主執行緒收集的到了 	4	執行緒的返回值
主執行緒收集的到了 	5	執行緒的返回值
主執行緒收集的到了 	6	執行緒的返回值
主執行緒收集的到了 	7	執行緒的返回值
主執行緒收集的到了 	8	執行緒的返回值
主執行緒收集的到了 	9	執行緒的返回值
10	個執行緒都跑完了,繼續主執行緒的工作
程式能夠正常完成題目的要求,即主執行緒會在十個執行緒都完成之後再進行後續工作

但是,上面的程式碼其實忽略了一個重要的特性,那就是future.get()其實是阻塞的,也就是說當我們嘗試用get獲取返回值的時候,如果當時執行緒還沒有跑完,這時候其實主執行緒就會一直等在這裡,直到該執行緒跑完並返回一個值。

因此,以上程式碼可以優化成如下所示:

public class TestCallable {
	public static void main(String[] args) throws Exception{
		int SIZE = 10;
		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
		//我們使用一個List來存放Callable的返回值
		List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
		for (int i = 0; i < SIZE; i++) {
			Thread.sleep(100);
			futures.add(cachedThreadPool.submit(new MyCallable()));
		}
		for (Future<Integer> future : futures) {
			Integer id = future.get();
			System.out.println("主執行緒收集的到了 \t" + id + "\t執行緒的返回值");
		}
		System.out.println(SIZE + "\t個執行緒都跑完了,繼續主執行緒的工作");
	}
}

控制檯的情況也跟上面的一樣。

還有一點值得注意的是,

主執行緒收集的到了 	0	執行緒的返回值
主執行緒收集的到了 	1	執行緒的返回值
主執行緒收集的到了 	2	執行緒的返回值
主執行緒收集的到了 	3	執行緒的返回值
主執行緒收集的到了 	4	執行緒的返回值
主執行緒收集的到了 	5	執行緒的返回值
主執行緒收集的到了 	6	執行緒的返回值
主執行緒收集的到了 	7	執行緒的返回值
主執行緒收集的到了 	8	執行緒的返回值
主執行緒收集的到了 	9	執行緒的返回值


其實執行緒9有可能比執行緒0先跑完,但是由於我們在建立Future的List的時候,是按照從0開始的,在future.get()獲取返回值的時候,也是先從0開始。

其實執行緒9有可能比執行緒0先跑完,但是由於我們在建立Future的List的時候,是按照從0開始的,在future.get()獲取返回值的時候,也是先從0開始。

其實要完成題目的要求,更好地是使用CountDownLatch來完成,後續我將會補上用CountDownLatch來完成的部落格。

相關推薦

Callable實現10執行之後進行操作

昨天一個碰到了一個題目:如何程式設計,使得主執行緒在跑完十個執行緒之後,再進行後續操作。看到這個問題,我的第一反應就是可以使用Callable來實現。因為實現執行緒有兩種方式,實現Callable介面或者實現Runnable介面(至於繼承Thread類,我覺得這個方式其實本質

java實現【有三執行ID分別是A、B、C,請有多線程式設計實現,在螢幕上迴圈列印10次ABC.】

該題應屬於生產者消費者模式一類 生產者消費者模式:根據標誌位來發訊息,實現對執行緒的控制。 直接貼答案了,請各位大蝦們指正哦。 建立三個執行緒 如下:ThreadA、ThreadB、ThreadC public class ThreadA implements Ru

JAVA多執行10執行處理1000個數據

import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import j

10執行按順序打印出0123456789

思路 1、通過公正瑣object對10個執行緒進行管理,喚醒所有執行緒或者阻塞等待。 2、通過orderNum通知下一個執行緒需要輸出的數字 程式碼 public class Printer { private static final

Linux平臺C++實現訊號量,同步執行

    使用Linux平臺上現有的訊號量sem_t相關的一組API,可以方便地進行執行緒同步。現在用pthread_mutex_t和pthread_cond_t相關的一組API實現訊號量機制。這組API包括:pthread_mutex_init,pthread_cond_init,pthread_mu

編寫10執行,第一執行從1加到10...

11、編寫10個執行緒,第一個執行緒從1加到10,第二個執行緒從11加到20...第十個執行緒從91加到100,最後再把十個執行緒結果相加。public class Accumulator exten

Callable實現帶有返回值的執行

我們都知道執行緒是沒有返回值的,在Runnable介面中,只有一個抽象的Run方法,使用Callable我們能夠實現帶有返回值得的執行緒,下面是一個demo /** * */ package com.mingrisoft.threadone; impo

筆記:Java實現執行A B C,BC執行執行執行A線

final Lock lc = new ReentrantLock(); .. run() { lc.lock(); ... lc.unlock(); } 可能開啟方式不對吧,沒實現! 改用join() 可以實現(BC與A以單執行緒模式執行),程式碼如下: package

Java多執行--三執行分別列印a,b,c.請執行實現迴圈列印15次abc

掃盲: 想想自己多執行緒解決生產消費者問題就知道個synchronized,真是慚愧 為做此題目特意學習新的多執行緒知識–ReentrantLock跟synchronized一樣都是Java中的可重入鎖(可以在內部鎖中拿到外部鎖) Con

一個關於執行的經典面試題,要求執行,按順序列印1,2,3,4,5.... 71,72,73,74, 75. 執行1先列印1,2,3,4,5, * 然後是執行2列印6,7,8,9,10, 然後是

package thread; /**  *   * 一個關於執行緒的經典面試題,要求用三個執行緒,按順序列印1,2,3,4,5.... 71,72,73,74, 75. 執行緒1先列印1,2,3,4,5,  * 然後是執行緒2列印6,7,8,9,10, 然後是執行緒3列印

js實現隨機選取10–100之間的10數字,存入一個數組,並排序

方法一: <!DOCTYPE html> <html><head><meta charset="utf-8"><title>好好學習天天向上</title><script type="text/j

訊號量(互斥鎖)實現執行交替列印

本文實現兩個執行緒交替列印,採用的是逐步新增程式碼,分析每一步程式碼的作用,若想要看最終版本可直接翻看後面的最終版本。(本文以訊號量為例,互斥鎖的實現只需將訊號量的函式換成相應的互斥鎖的函式,互斥鎖(訊號量)函式不知道的看https://blog.csdn.net/liqia

ConcurrentHashMap原理(2)之分離鎖實現執行間的併發寫操作

ConcurrentHashMap 類 ConcurrentHashMap 在預設併發級別會建立包含 16 個 Segment 物件的陣列。每個 Segment 的成員物件 table 包含若干個散列表的桶。每個桶是由 HashEntry 連結起來的一個連結串列。如果鍵能均

教育,創新,提升:Indiegogo和Kickstarter上受中國戶支持的10眾籌項目

即將 school -c 藝術家 new 技術分享 www ouya 積極 中國的經濟正在迅速發展,已成為世界第二大經濟體。中國家庭隨著經濟水平的提高,越來越多父母願意將自己的子女送到海外留學。 家長們希望自己的子女可以有機會接受國外大學優質的教育, 以便他們將來可以學成歸

究極難題 :一個執行10秒以上至無窮的呼叫函式,成功後有返回值。在多工執行中怎麼實現呼叫不卡住該執行

究極難題 :一個執行10秒以上至無窮的呼叫函式,成功後有返回值。在多工執行緒中怎麼實現呼叫不卡住該執行緒? Note:一旦呼叫函式,中途無法取消。 思路一:讓其執行在獨立執行緒內。加超時時間。 1. 在超時時間內函式有返回值,則函式執行結束。則獨立執行緒結束。 2. 在超時時

面向物件重寫thread 實現多次呼叫一個執行

思路:   利用thread類中,run方法在子執行緒中呼叫,其他方法在主執行緒呼叫,所以將生產者寫入主執行緒,將消費者寫入run函式中在子執行緒中執行,完成生產者消費者模型 注意:   1.  要在 init 函式中例項化一個Queue佇列作為生產者消費者中介   2.  要在 init 函式中把d

Java-執行(十執行實現1~100求和)

這道題我大概搞了兩個小時左右吧。 可是我發現總是不對,最後發現我做不出來了,因為我並未真正搞清整個程式的執行,以及對那些關鍵詞(我指的是synchronized、wait()、notify()等這些玩意兒)的理解和使用都不清楚,更別說寫出來整個程式了。 public class Fort

java實現執行達到一個闕伐值後一起執行

給大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油 1. CountDownLatch 1.1 簡介 CountDownLatch是一個同步輔助類,通過它可以完成類似於阻塞當前執行緒的功能,即:一個執行緒或多個執行緒一直等待,直到其他執行緒執行的操作完成。CountDownLatch用

執行同步之——兩執行序列順序列印奇數和偶數的兩種實現

題目:一道經典的執行緒併發的問題,執行緒a列印1、3、5……,執行緒b列印2、4、6……,兩個執行緒交替執行輸出1、2、3、4、5、6…… 要點: package com.test; import java.util.concurrent.locks.

現在有T1、T2、T3三執行,你怎樣保證T2在T1執行執行,T3在T2執行執行

這是個基礎的執行緒問題,主要是考核join方法的。不瞭解這個方法的話會感覺很懵逼。 假設現在有兩個執行緒A、B。如果在A的run方法中呼叫B.join(),表示A需要在B執行緒上面等待,也就是需要在B執行緒執行完成之後才能再次執行。瞭解這個概念之後,這個問題就很簡單了,java程式碼如下: