多线程交替输出多种方式实现(附代码案例)
原题如下:用两个线程实现交替输出AB,每个线程输出10次,
结果如下:ABABABABABABABABABAB
以下代码附带 LockSupport使用案例,Lock和Condition使用案例,Semaphore信号量使用案例,Object.wait()和Object.notify()使用案例
实现方式:
- 方式1:每个线程自旋获取是否打印标识,利用原子类实现(AtomicInteger),实现简单但是性能不友好
- 方式2:利用LockSupport阻塞和唤醒机制实现对应线程的调度
- 方式3:利用Lock和Condition阻塞和唤醒机制实现对应线程的调度 ,和3一样
- 方式4:利用Semaphore信号量控制该线程是否打印(推荐解法1)
- 方式5:利用Object的wait/notify 阻塞和唤醒机制
- 方式6:利用ReentrantLock的公平锁机制(推荐解法2)
- 方式7:利用BlockingQueue阻塞队列实现(原理和信号量相似,底层使用Condition实现的)
方式1代码:
//true线程1打印,flase线程2打印AtomicBoolean flag = new AtomicBoolean(true);AtomicInteger printTimes = new AtomicInteger(0);void print() {new Thread(() -> {while (true) {if (flag.get()) {int times = printTimes.incrementAndGet();if (times <= 20) {System.out.println("A");//通知另一个线程工作,通知工作要在打印工作之后设置,否则另一个线程可能先于发生flag.set(false);} else {flag.set(false);break;}}}}).start();new Thread(() -> {while (true) {if (!flag.get()) {int times = printTimes.incrementAndGet();if (times <= 20) {System.out.println("B");flag.set(true);} else {flag.set(true);break;}}}}).start();}
方式2代码:LockSupport方式
class PrintA extends Thread {Thread next;//为了引入下一个线程void setNext(Thread next) {this.next = next;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("A");//线程1先阻塞,线程2start后会先唤醒线程1再阻塞,然后线程1唤醒线程2,如此实现循环LockSupport.park();LockSupport.unpark(next);}}}class PrintB extends Thread {Thread next;void setNext(Thread next) {this.next = next;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("B");LockSupport.unpark(next);LockSupport.park();}}}void print() {PrintA t1 = new PrintA();PrintB t2 = new PrintB();t1.setNext(t2);t2.setNext(t1);t1.start();try {//确保t1已经阻塞了Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}t2.start();}
方式3: Lock和Condition的方式,和方式3逻辑一样的
Lock lock = new ReentrantLock();Condition c1 = lock.newCondition();Condition c2 = lock.newCondition();void print() {new Thread(() -> {for (int i = 0; i < 10; i++) {lock.lock();try {System.out.println("A");//c1先阻塞,t2唤醒c1,c2阻塞,t1唤醒c2,如此循环和LockSupport一样的逻辑c1.await();c2.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}).start();try {//确保t1已经阻塞Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {for (int i = 0; i < 10; i++) {lock.lock();try {System.out.println("B");c1.signal();c2.await();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}).start();}
方式4:Semaphore 信号量
void print() {Semaphore semaphore1 = new Semaphore(1);Semaphore semaphore2 = new Semaphore(0);new Thread(()-> {for (int i = 0; i < 10; i++) {try {semaphore1.acquire();System.out.println("A");semaphore2.release();} catch (InterruptedException e) {e.printStackTrace();}}}).start();//Thread.sleep(1000L),相比于方法3&4这里的睡眠时间不需要了// semaphore2信号量初始化为0,t2线程执行acquire()会阻塞,当t1执行semaphore2.release()后t2才会执行new Thread(()-> {for (int i = 0; i < 10; i++) {try {semaphore2.acquire();System.out.println("B");semaphore1.release();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
方式5:Object.wait()和notify()
Object object = new Object();void print() {new Thread(() -> {synchronized (object) {for (int i = 0; i < 10; i++) {object.notify();System.out.println("A");try {object.wait();} catch (InterruptedException e) {e.printStackTrace();}}object.notify();}}).start();//想要A先输出,这里得sleep,否则有可能输出BABAThread.sleep(100L);new Thread(() -> {synchronized (object) {for (int i = 0; i < 10; i++) {object.notify();System.out.println("B");try {object.wait();} catch (InterruptedException e) {e.printStackTrace();}}object.notify();}}).start();}
方式6:ReentranLock公平锁
Lock lock = new ReentrantLock(true);volatile int printFlag = 0;void print() {new Thread(() -> {for (int i = 0; i < 10; ) {lock.lock();try {if(printFlag == 0){System.out.println("A");i++;printFlag = 1;}} finally {lock.unlock();}}}).start();new Thread(() -> {for (int i = 0; i < 10;) {lock.lock();try {if(printFlag == 1){System.out.println("B");i++;printFlag = 0;}} finally {lock.unlock();}}}).start();
方式7:阻塞队列
private BlockingQueue queueA = new LinkedBlockingQueue() {{add(0);}};private BlockingQueue queueB = new LinkedBlockingQueue<>();void print() {new Thread(() -> {for (int i = 0; i < 10; i++ ) {try {queueA.take();System.out.println("A");queueB.add(0);} catch (InterruptedException e) {e.printStackTrace();}}}).start();new Thread(() -> {for (int i = 0; i < 10;i++) {try {queueB.take();System.out.println("B");queueA.add(0);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
