網頁

2018/12/8

Java 使用Callable Multi-thread 處理 LeetCode Jewels and Stones 珠寶與石頭

本篇源自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())測了一下確實有多執行緒的效果,但問題是多執行緒的速度卻比原本單執行緒結果還慢? 因為我對多執行緒不熟,所以目前不知道原因。


參考:

沒有留言:

張貼留言