java实现三个线程交替打印ABC

两种方式实现:

  • Semaphore
  • volatile变量

使用Semaphore

思路, 三个信号量, a控制b, b控制c, c控制a
初始情况, a开启, bc关闭

public class printByTurn {
    
    

    private static Semaphore[] semaphores = new Semaphore[3];
    

    static {
    
    //初始情况
        for(int i=0; i<semaphores.length; i++){
    
    
            if(i==0) semaphores[i] = new Semaphore(1);
            else semaphores[i] = new Semaphore(0);
        }
    }

    static class thread extends Thread {
    
    
        private int num;//当前线程对应信号量索引
        private char printDigit;//当前线程打印字符

        public thread(int num, char printDigit){
    
    
            this.num = num;
            this.printDigit = printDigit;
        }

        @Override
        public void run() {
    
    
            try{
    
    
                for(int i=0; i<10; i++){
    
    
                    semaphores[this.num].acquire();
                    System.out.println(printDigit);
                    semaphores[(this.num+1)%3].release();                   
                }
            }
            catch (Exception e){
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        new thread(0,'A').start();
        new thread(1,'B').start();
        new thread(2,'C').start();
    }
}

使用volatile修饰的变量

public class printByTurn {
    
    

    private static volatile boolean[] valatiles = new boolean[3];

    static {
    
    
        for(int i=0; i<semaphores.length; i++){
    
    
            if(i==0) valatiles[i] = true;
            else valatiles[i] = false;
        }
    }

    static class thread extends Thread {
    
    
        private int num;
        private char printDigit;

        public thread(int num, char printDigit){
    
    
            this.num = num;
            this.printDigit = printDigit;
        }

        @Override
        public void run() {
    
    
            try{
    
    
                int i = 0;
                while(true){
    
    
	                if(valatiles[num]){
    
    
	                    valatiles[num] = false;
	                    System.out.println(printDigit);
	                    valatiles[(num+1)%3] = true;
	                    i++;
	                }
	                if(i>=10) break;
                }
            }
            catch (Exception e){
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        new thread(0,'A').start();
        new thread(1,'B').start();
        new thread(2,'C').start();
    }
}

二者比较

  • 前者使用juc提供的信号量, 通过aqs提供的机制, 实现线程的阻塞与线程的切换. 对于任务不是那么密集的场景, 信号量比较适合. 但如果任务密集, 则会疯狂的线程上下文切换, 内核态和用户态切换, 极其的影响性能.
  • 后者使用volatile关键字, 通过volatile关键字来保证变量的可见性, 通过变量来控制当前是否打印, 然后每次打印过程就是先灭自己, 再点亮别人. 可以看到, 因为没有办法实现线程的阻塞, 这里实际是一个自旋锁, cpu会空转, 所以比较适合密集切换的任务. 对于不密集的任务, cpu空转十分消耗资源, 不如释放cpu的使用权, 采用前者方案.

Guess you like

Origin blog.csdn.net/qq_34687559/article/details/118436470