Java基礎-線程併發工具類

Android知識終結

一、分而治之原理(fork/join )

在計算機十大經典算法中,快速排序歸併排序二分查找用的是分而治之原理。

1、定義

在Java的Fork/Join框架中,使用兩個類完成上述操作

  • 1、ForkJoinTask:我們要使用Fork/Join框架,首先需要創建一個ForkJoin任務。該類提供了在任務中執行fork和join的機制。通常情況下我們不需要直接集成ForkJoinTask類,只需要繼承它的子類,Fork/Join框架提供了兩個子類:
  • RecursiveTask同步用法同時演示有返回結果,統計整形數組中所有元素的和。
  • RecursiveAction異步用法同時演示不要求返回值,遍歷指定目標(含子目錄)尋找指定類型文件。
  • 2、ForkJoinPool:ForkJoinTask需要通過ForkJoinPool來執行。
  • 任務分割出的子任務會添加到當前工作線程所維護的雙端隊列中,進入隊列的頭部。當一個工作線程的隊列裏暫時沒有任務時,它會隨機從其他工作線程的隊列的尾部獲取一個任務(工作竊取算法)。

2、歸併排序-同步用法

2.1、數組集合

public class MakeArray {
    public static final int MAX_COUNT = 40000;

    public static int[] getArrays(){
        int[] nums = new int[MAX_COUNT];
        Random random = new Random();
        for (int i = 0; i < MAX_COUNT; i++) {
            nums[i] = random.nextInt(MAX_COUNT);
        }
        return nums;
    }
}

2.2、求數組中的和

public class SunArray {
    public static class SumTask extends RecursiveTask<Integer>{
        private static final int THRESHOLD = MakeArray.MAX_COUNT/10;
        private int[] nums;
        private int fromIndex;
        private int toIndex;

        public SumTask(int[] nums, int fromIndex, int toIndex) {
            this.nums = nums;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }

        @Override
        protected Integer compute() { //運用遞歸算法
            if (toIndex - fromIndex < THRESHOLD){
                System.out.println("form index = " + fromIndex + "toIndex = " + toIndex);
                int count = 0;
                for (int i = fromIndex; i < toIndex; i++) {
                    count += nums[i];
                }
                return count;
            } else {
                int mid = (toIndex + fromIndex) / 2;
                SumTask left = new SumTask(nums, fromIndex, mid);
                SumTask right = new SumTask(nums, mid, toIndex);
                invokeAll(left, right);
                return left.join() + right.join();
            }
        }
    }
    
    public static void main(String[] argc){
        int[] arrays = MakeArray.getArrays();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SumTask sumTask = new SumTask(arrays, 0, arrays.length);
        long start = System.currentTimeMillis();
        forkJoinPool.invoke(sumTask);
        System.out.println("The count is" + sumTask.join() +
                "spend time" + (System.currentTimeMillis() - start) + "ms");
    }
}

3、異步用法

/**
 *類說明:遍歷指定目錄(含子目錄)找尋指定類型文件
 */
public class FindDirsFiles extends RecursiveAction {
    private File path;
    public FindDirsFiles(File path) {
        this.path = path;
    }
    @Override
    protected void compute() {
        List<FindDirsFiles> subTasks = new ArrayList<>();
        File[] files = path.listFiles();
        if (files!=null){
            for (File file : files) {
                if (file.isDirectory()) {
                    // 對每個子目錄都新建一個子任務。
                    subTasks.add(new FindDirsFiles(file));
                } else {
                    // 遇到文件,檢查。
                    if (file.getAbsolutePath().endsWith("txt")){
                        System.out.println("文件:" + file.getAbsolutePath());
                    }
                }
            }
            if (!subTasks.isEmpty()) {
                // 在當前的 ForkJoinPool 上調度所有的子任務。
                for (FindDirsFiles subTask : invokeAll(subTasks)) {
                    subTask.join();
                }
            }
        }
    }

    public static void main(String [] args){
        try {
            // 用一個 ForkJoinPool 實例調度總任務
            ForkJoinPool pool = new ForkJoinPool();
            FindDirsFiles task = new FindDirsFiles(new File("F:/"));

            /*異步提交*/
            pool.execute(task);
            /*主線程做自己的業務工作*/
            System.out.println("Task is Running......");
            Thread.sleep(1);
            int otherWork = 0;
            for(int i=0;i<100;i++){
                otherWork = otherWork+i;
            }
            System.out.println("Main Thread done sth......,otherWork=" +otherWork);
            task.join();//阻塞方法
            System.out.println("Task end");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

二、CountDownLatch 計數器

  • countDownLatch這個類使一個線程等待其他線程各自執行完畢後再執行。
  • 是通過一個計數器來實現的,計數器的初始值是線程的數量。每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,閉鎖上等待的線程就可以恢復工作了。
  • 使用AQS的共享方式,內部實現了AbstractQueuedSynchronizer的內部類。
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        Sync(int count) {
            setState(count);
        }
        int getCount() {
            return getState();
        }
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

注意:一個線程可以多次減一;閉鎖線程可以有多個且閉鎖線程執行任務時其他線程可能還在執行

示例演示

/**
 *類說明:演示CountDownLatch用法,
 * 共5個初始化子線程,6個閉鎖釦除點,扣除完畢後,主線程和業務線程才能繼續執行
 */
public class UseCountDownLatch {
    static CountDownLatch latch = new CountDownLatch(6);
    /*初始化線程*/
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("Thread_" + Thread.currentThread().getId()
                    + " ready init work......");
            latch.countDown();
            for (int i = 0; i < 2; i++) {
                System.out.println("Thread_" + Thread.currentThread().getId()
                        + " ........continue do its work");
            }
        }
    }

    /*業務線程等待latch的計數器爲0完成*/
    private static class MyThread implements Runnable {
        @Override
        public void run() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 3; i++) {
                System.out.println("BusiThread_" + Thread.currentThread().getId()
                        + " do business-----");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1);
                    System.out.println("Thread_" + Thread.currentThread().getId()
                            + " ready init work step 1st......");
                    latch.countDown();
                    System.out.println("begin step 2nd.......");
                    Thread.sleep(1);
                    System.out.println("Thread_" + Thread.currentThread().getId()
                            + " ready init work step 2nd......");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new MyThread()).start();
        for (int i = 0; i <= 3; i++) {
            Thread thread = new Thread(new MyRunnable());
            thread.start();
        }
        latch.await();
        System.out.println("Main do ites work........");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章