Callable in Java with Examples - Java 147

Callable in Java with Examples – Java 147

Callable in Java with Examples

定義了一個 泛型 V 傳回值的 call 方法,會拋出檢查例外,因此可輕易地將例外往外傳遞,當任務完成時使用 Future 儲存不同執行緒的結果, Callable Java 基本上是主執行緒可以追踪其他執行緒的進度結果的一種方式,FutureTask 實作了 Runnable 和 Future 介面,方便地結合了這兩種功能, Callable in Java 本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- multithreading
       |                   +- callable
       |                       +- CallableWithExamplesTest.java   

單元測試

Callable Java 提供執行任務、拋出例外、傳回值等操作。

worker

Callable Java 建立 3 條執行緒,執行 3 個任務,每個任務耗時 3 秒完成,主執行緒會無限等待取得每個任務結束後的傳回值。

	protected class Worker implements Callable<Object> {

		private int id;
		private Object result;

		public Worker(int id) {
			this.id = id;
		}

		public int getId() {
			return id;
		}

		@Override
		public Object call() throws Exception {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");

			result = "OK";
			return result;
		}
	}

	@Test
	public void worker() {
		try {
			int taskSize = 3;
			List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
			for (int i = 0; i < taskSize; i++) {
				FutureTask<Object> futureTask = new FutureTask<Object>(new Worker(i));
				futureTasks.add(futureTask);
				Thread thread = new Thread(futureTask);
				thread.start();
			}

			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			futureTasks.forEach(e -> {
				try {
					Object result = e.get();
					System.out.println(
							sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
2023/02/07 08:20:39 T[12] worker: 1 ready
2023/02/07 08:20:39 T[11] worker: 0 ready
2023/02/07 08:20:39 T[13] worker: 2 ready
2023/02/07 08:20:42 T[13] worker: 2 finished
2023/02/07 08:20:42 T[12] worker: 1 finished
2023/02/07 08:20:42 T[11] worker: 0 finished
2023/02/07 08:20:42 T[1] worker: OK
2023/02/07 08:20:42 T[1] worker: OK
2023/02/07 08:20:42 T[1] worker: OK

brokenWorker

Callable Java 建立 3 條執行緒,執行 3 個任務,每個任務耗時 1 秒完成,其中 1 條執行緒拋出例外,主執行緒會無限等待取得每個任務結束後的傳回值。

	protected class BrokenWorker implements Callable<Object> {

		private int id;
		private Object result;

		public BrokenWorker(int id) {
			this.id = id;
		}

		public int getId() {
			return id;
		}

		@Override
		public Object call() throws Exception {
			if (id == 1) {
				throw new RuntimeException("BrokenWorker " + id + " throw exception");
			}
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");

			result = "OK";
			return result;
		}
	}

	@Test
	public void brokenWorker() {
		try {
			int taskSize = 3;
			List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
			for (int i = 0; i < taskSize; i++) {
				FutureTask<Object> futureTask = new FutureTask<Object>(new BrokenWorker(i));
				futureTasks.add(futureTask);
				Thread thread = new Thread(futureTask);
				thread.start();
			}

			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			futureTasks.forEach(e -> {
				try {
					Object result = e.get();
					System.out.println(
							sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
2023/02/07 08:22:17 T[16] worker: 2 ready
2023/02/07 08:22:17 T[14] worker: 0 ready
2023/02/07 08:22:20 T[14] worker: 0 finished
2023/02/07 08:22:20 T[16] worker: 2 finished
2023/02/07 08:22:20 T[1] worker: OK
java.util.concurrent.ExecutionException: java.lang.RuntimeException: BrokenWorker 1 throw exception
2023/02/07 08:22:20 T[1] worker: OK
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at org.ruoxue.java_147.multithreading.CallableWithExamplesTest.lambda$1(CallableWithExamplesTest.java:114)
	at java.util.ArrayList.forEach(ArrayList.java:1257)

CallableWithExamplesTest.java

Java Runnable 新增單元測試,驗證是否符合預期。

package org.ruoxue.java_147.multithreading.callable;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class CallableWithExamplesTest {

	protected class Worker implements Callable<Object> {

		private int id;
		private Object result;

		public Worker(int id) {
			this.id = id;
		}

		public int getId() {
			return id;
		}

		@Override
		public Object call() throws Exception {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");

			result = "OK";
			return result;
		}
	}

	@Test
	public void worker() {
		try {
			int taskSize = 3;
			List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
			for (int i = 0; i < taskSize; i++) {
				FutureTask<Object> futureTask = new FutureTask<Object>(new Worker(i));
				futureTasks.add(futureTask);
				Thread thread = new Thread(futureTask);
				thread.start();
			}

			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			futureTasks.forEach(e -> {
				try {
					Object result = e.get();
					System.out.println(
							sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	protected class BrokenWorker implements Callable<Object> {

		private int id;
		private Object result;

		public BrokenWorker(int id) {
			this.id = id;
		}

		public int getId() {
			return id;
		}

		@Override
		public Object call() throws Exception {
			if (id == 1) {
				throw new RuntimeException("BrokenWorker " + id + " throw exception");
			}
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");

			result = "OK";
			return result;
		}
	}

	@Test
	public void brokenWorker() {
		try {
			int taskSize = 3;
			List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
			for (int i = 0; i < taskSize; i++) {
				FutureTask<Object> futureTask = new FutureTask<Object>(new BrokenWorker(i));
				futureTasks.add(futureTask);
				Thread thread = new Thread(futureTask);
				thread.start();
			}

			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
			futureTasks.forEach(e -> {
				try {
					Object result = e.get();
					System.out.println(
							sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

心得分享

Callable in Java Multithreading 提供建立新執行緒,執行指定任務,使用 Java Callable 可以拋出設計階段的檢查例外,像是: IOException ,及取得不同執行緒的結果,多執行緒一直以來,都是 Java 的主要方面,使用 Callable Java 進而優化系統資源,提升執行效率。

發佈留言