本篇源自LeetCode Jewels and Stones 珠寶與石頭的問題,想說是否可以用多執行緒來處理看看。本篇只是練習如何使用Callable
返回值。
想法是把代表石頭的字串分為前後兩半,分別交給兩個執行緒來處理,處理完返回屬於珠寶的數目。
因為執行緒Runnable
無法返回值,所以改用Callable
。
建立NumJewelsInStonesTask
類別繼承Callable
介面,並在實作的Callable.call()
方法呼叫找出珠寶的方法numJewelsInStones()
。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
public class NumJewelsInStonesTask implements Callable<Integer> {
private String J;
private String S;
public NumJewelsInStonesTask(String J, String S) {
this.J = J;
this.S = S;
}
@Override
public Integer call() throws Exception {
return numJewelsInStones(J, S);
}
private int numJewelsInStones(String J, String S) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (char j : J.toCharArray()) {
map.put(j, 1);
}
int count = 0;
for (char s : S.toCharArray()) {
if (map.get(s) != null) {
count++;
}
}
return count;
}
}
測試
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.text.RandomStringGenerator;
public class App {
public static void main(String[] args) throws InterruptedException, ExecutionException {
String J = "aAbBcCdDeEfFgG"; // 珠寶種類
String S = genRandomLengthString(100000000); // 產生 "a - z", "A - Z"隨機字串, 長度=100000000
long startTime = System.nanoTime();
int jewelNumber = numJewelsInStones(J, S);
long endTime = System.nanoTime();
System.out.println("Jewel Number:" + jewelNumber);
System.out.println("Execution Time:" + (endTime - startTime) + " nanosecond");
}
private static String genRandomLengthString(int length) {
char[][] pairs = { { 'a', 'z' }, { 'A', 'Z' } }; // 隨機字串範圍
RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange(pairs).build();
return generator.generate(length); // 產生 "a - z", "A - Z"隨機字串
}
private static int numJewelsInStones(String J, String S) throws InterruptedException, ExecutionException {
NumJewelsInStonesTask task1 = new NumJewelsInStonesTask(J, S.substring(0, S.length() / 2));
NumJewelsInStonesTask task2 = new NumJewelsInStonesTask(J, S.substring(S.length() / 2));
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
int count1 = future1.get();
int count2 = future2.get();
if (future1.isDone() && future2.isDone()) {
executor.shutdown();
}
return count1 + count2;
}
}
使用 System.out.println(Thread.currentThread().getName())
測了一下確實有多執行緒的效果,但問題是多執行緒的速度卻比原本單執行緒結果還慢? 因為我對多執行緒不熟,所以目前不知道原因。
參考:
沒有留言:
張貼留言