スレッドプールのタスク調整と共有データの取り扱い

スレッド間の通信と同期

1. スレッドAが完了した後にスレッドBを実行する

    
    /**
     * Aが完了した後にBを実行
     */
    @Test
    public void bWaitA() {
        Thread A = new Thread(() -> {
            System.out.println("A: 作業開始!!");
            System.out.println("A: 作業終了!!");
        });
        Thread B = new Thread(() -> {
            System.out.println("B: Aの完了を待つ");
            try {
                A.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B: 作業開始!!");
            System.out.println("B: 作業終了!!");
        });
        B.start();
        A.start();
    }
    
  

2. Aが一部を実行し、Bが完了した後にAが残りを実行する

    
    /**
     * Aが一部を実行し、Bが完了した後にAが残りを実行
     * A 1, B 1, B 2, B 3, A 2, A 3
     */
    @Test
    public void aWaitB() {
        Object lock = new Object();
        Thread A = new Thread(() -> {
            System.out.println("A: ロック待ち");
            synchronized (lock) {
                System.out.println("A: ロック取得");
                System.out.println("A 1");
                try {
                    System.out.println("A: waitでロック解放、再取得待ち");
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("A: 唤醒后,重新获取锁控制权");
                System.out.println("A 2");
                System.out.println("A 3");
            }
        });
        Thread B = new Thread(() -> {
            System.out.println("B: ロック制御権取得待ち");
            synchronized (lock) {
                System.out.println("B: ロック制御権取得");
                System.out.println("B 1");
                System.out.println("B 2");
                System.out.println("B 3");
                System.out.println("B: 完了、notify呼び出し");
                lock.notify();
            }
        });
        A.start();
        B.start();
    }
    
  

3. A, B, Cが完了した後にDを実行する

    
    /**
     * A, B, Cが完了した後にDを実行
     */
    @Test
    public void dWaitABC() {
        int worker = 3;
        CountDownLatch countDownLatch = new CountDownLatch(worker);
        new Thread(() -> {
            System.out.println("D: 他のスレッドの完了待ち");
            try {
                countDownLatch.await();
                System.out.println("すべてのスレッドが完了、D開始");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        for (char threadName = 'A'; threadName <= 'C'; threadName++) {
            final String threadNameStr = String.valueOf(threadName);
            new Thread(() -> {
                System.out.println(threadNameStr + ": 作業中");
                System.out.println(threadNameStr + ": 作業完了");
                countDownLatch.countDown();
            }).start();
        }
    }
    
  

4. 三人の選手が準備完了後同時に走り出す

    
    /**
     * 三人の選手が準備完了後同時に走り出す
     */
    @Test
    public void runABCWhenAllReady() {
        int runner = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
        final Random random = new Random();
        for (char runnerName = 'A'; runnerName <= 'C'; runnerName++) {
            final String runnerNameStr = String.valueOf(runnerName);
            new Thread(() -> {
                long prepareTime = random.nextInt(1000) + 100;
                System.out.println(runnerNameStr + ": 準備中");
                try {
                    Thread.sleep(prepareTime);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    System.out.println(runnerNameStr + ": 準備完了、他のスレッド待ち");
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("すべてのスレッドが準備完了、" + runnerNameStr + " 開始");
            }).start();
        }
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
  

5. スレッド間のデータ共有

    
    /**
     * スレッド間のデータ共有
     */
    @Test
    public void shareData() {
        ShareData shareData = new ShareData();
        for (int i = 1; i <= 2; i++) {
            new Thread(new MyIncreRunnable(shareData)).start();
            new Thread(new MyDecreRunanble(shareData)).start();
        }
    }

    class MyIncreRunnable implements Runnable {
        private ShareData shareData;

        public MyIncreRunnable(ShareData shareData) {
            this.shareData = shareData;
        }

        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                shareData.increment();
            }
        }
    }

    class MyDecreRunanble implements Runnable {
        private ShareData shareData;

        public MyDecreRunanble(ShareData shareData) {
            this.shareData = shareData;
        }

        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                shareData.decrement();
            }
        }
    }

    class ShareData {
        private int count = 0;

        public synchronized void increment() {
            count++;
            System.out.println(Thread.currentThread().getName() + " inc " + count);
        }

        public synchronized void decrement() {
            count--;
            System.out.println(Thread.currentThread().getName() + " dec " + count);
        }
    }
    
  

タグ: Java スレッド タスク調整 共有データ CountDownLatch

6月19日 22:15 投稿