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的使用权, 采用前者方案.
上一篇:
通过多线程提高代码的执行效率例子