多线程循环打印ABC

序言

多线程的使用是开发极其重要的一环,本篇文章介绍三种方式,让线程循环打印ABC,其中涉及JUC下面的三个重要工具类。

Semaphore实现

package org.example.exercise;

import java.util.concurrent.Semaphore;

public class TestWeiLai1 {

    public static void main(String[] args) {
        Semaphore aSemaphore = new Semaphore(1);
        Semaphore bSemaphore = new Semaphore(0);
        Semaphore cSemaphore = new Semaphore(0);


        new Thread(new MyRunnable(aSemaphore, bSemaphore, "A")).start();
        new Thread(new MyRunnable(bSemaphore, cSemaphore, "B")).start();
        new Thread(new MyRunnable(cSemaphore, aSemaphore, "C")).start();
    }

     static class MyRunnable implements Runnable {
        private final Semaphore current;
        private final Semaphore next;
        private final String str;

        public MyRunnable(Semaphore current, Semaphore next, String str) {
            this.current = current;
            this.next = next;
            this.str = str;
        }

        @Override
        public void run() {
            try {
                for (int i = 0;i < 3;i++) {
                    current.acquire();
                    System.out.println(str);
                    next.release();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}

CyclicBarrier实现

package org.example.exercise;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class TestWeiLai2 {

    private static int count = 0;
    private static final String arr = "ABC";

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
        });

        Runnable runnable = () -> {
            for (int i = 0;i < 3;i++) {
                count = count > 2 ? 0 : count;
                synchronized (TestWeiLai2.class) {
                    System.out.println(arr.charAt(count++));
                }
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }

}

CountDownLatch实现

package org.example.exercise;

import java.util.concurrent.CountDownLatch;

public class TestWeiLai3 {

    static CountDownLatch countDownLatchA = new CountDownLatch(1);
    static CountDownLatch countDownLatchB = new CountDownLatch(1);
    static CountDownLatch countDownLatchC = new CountDownLatch(1);

    public static void main(String[] args) {
        new Thread(() -> {
            for (int i = 0;i < 3;i++) {
                try {
                    countDownLatchA.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("A");
                countDownLatchA = new CountDownLatch(1);
                countDownLatchB.countDown();
            }
        }).start();

        new Thread(() -> {
            for (int i = 0;i < 3;i++) {
                try {
                    countDownLatchB.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("B");
                countDownLatchB = new CountDownLatch(1);
                countDownLatchC.countDown();
            }
        }).start();

        new Thread(() -> {
            for (int i = 0;i < 3;i++) {
                try {
                    countDownLatchC.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("C");
                countDownLatchC = new CountDownLatch(1);
                countDownLatchA.countDown();
            }
        }).start();

        countDownLatchA.countDown();
    }

}

总结

从上述三种方式可以看到三种方式实现各不相同,具体如下

  • Semaphore实现主要是通过获取信号量、释放信号量构建线程之前的同步循环
  • CyclicBarrier是使用它的特性,当所有线程都到屏障时才结束等待,同时用锁对共享计数器递增,从而实现循环打印
  • CountDownLatch较为复杂,由于其只能减而不能增,因此无法封装一个统一的方法进行操作,需要对原有变量更改,所以需要使用完之后,new新的实例给原有变量,从而构建线程之间的同步循环,实现循环打印
end

评论