三个线程循环的按顺序打印

问题是:启动3个线程顺序打印ABC 10次,不能使用sleep。
方案一:

public class ThreadDemo{public static void main(String[] args) {MyLock lock = new MyLock(); Thread a = new Thread(new MyPrinter("A", "B", lock)); Thread b = new Thread(new MyPrinter("B", "C", lock)); Thread c = new Thread(new MyPrinter("C", "A", lock)); a.start(); b.start(); c.start(); lock.setHolder("A"); }static class MyPrinter implements Runnable {private String myName; private String nextName; private final MyLock lock; public MyPrinter(String myName, String nextName, MyLock lock) { this.myName = myName; this.nextName = nextName; this.lock = lock; }public void run() { int count = 3; while (count > 0) { if (lock != null && lock.getHolder() != null && lock.getHolder().equals(myName)) { synchronized (lock) { System.out.print(myName); count--; lock.setHolder(nextName); } }} } }static class MyLock {public MyLock() { } private String holder; public String getHolder() { return holder; }public void setHolder(String holder) { this.holder = holder; } } }


方案二:
对上一个方案进行修改:把count定义为static,不然每个线程之间可没法共享count变量,且由于是输出后再--,故设置成9比较合适。

public class ThreadDemo{public static void main(String[] args) {MyLock lock = new MyLock(); Thread a = new Thread(new MyPrinter("A", "B", lock)); Thread b = new Thread(new MyPrinter("B", "C", lock)); Thread c = new Thread(new MyPrinter("C", "A", lock)); a.start(); b.start(); c.start(); lock.setHolder("A"); }static class MyPrinter implements Runnable {private String myName; private String nextName; private final MyLock lock; static int count = 9; public MyPrinter(String myName, String nextName, MyLock lock) { this.myName = myName; this.nextName = nextName; this.lock = lock; }public void run() { while (count > 0) { if (lock != null && lock.getHolder() != null && lock.getHolder().equals(myName)) { synchronized (lock) { System.out.print(myName); count--; lock.setHolder(nextName); } }} } }static class MyLock {public MyLock() { } private String holder; public String getHolder() { return holder; }public void setHolder(String holder) { this.holder = holder; } } }


方案三:
本质应该是操作系统中的同步问题,设定好信号量,使用PV元语就可以。要用java实现的话,使用wait()和notify()应该就OK。


public class ThreadDemo { public static void main(String[] args) { final int count = 3; String[] abc = { "a", "b", "c" }; for (int i = 0; i < abc.length; i++) { final String current = abc[i]; final String next = abc[(i + 1) % abc.length]; new Thread(new Runnable() { public void run() { for (int j = 0; j < count; j++) { synchronized (current) { // 等待信号 try { current.wait(); } catch (InterruptedException e) { } System.out.print(current); // 给下个线程发信号synchronized (next) { next.notify(); } } } } }).start(); } // 通给第一个线程发信号 synchronized (abc[0]) { abc[0].notify(); } } }




可用用如下方式分析(参考)

public class ThreadDemo { public static void main(String[] args) { final int count = 3; String[] abc = { "a", "b", "c" }; for (int i = 0; i < abc.length; i++) { final String current = abc[i]; final String next = abc[(i + 1) % abc.length]; new Thread(new Runnable() { public void run() { for (int j = 0; j < count; j++) { synchronized (current) { // 等待信号 System.out.println(current + "等待信号"); try { current.wait(); } catch (InterruptedException e) { } System.out.println(current + "给下一个线程发信号"); // 给下个线程发信号synchronized (next) { next.notify(); } } System.out.println("第" + j + "次循环"); } } }).start(); } // 通给第一个线程发信号 System.out.println("给第一个线程发信号"); synchronized (abc[0]) { abc[0].notify(); } } }


方案四:

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadDemo { private static Lock lock = new ReentrantLock(); //通过JDK5中的锁来保证线程的访问的互斥 private static int state = 0; static class ThreadA extends Thread { @Override public void run() { for (int i = 0; i < 3; ) { lock.lock(); if (state % 3 == 0) { System.out.print("A"); state++; i++; } lock.unlock(); } } }static class ThreadB extends Thread { @Override public void run() { for (int i = 0; i < 3; ) { lock.lock(); if (state % 3 == 1) { System.out.print("B"); state++; i++; } lock.unlock(); } } }static class ThreadC extends Thread { @Override public void run() { for (int i = 0; i < 3; ) { lock.lock(); if (state % 3 == 2) { System.out.print("C"); state++; i++; } lock.unlock(); } } }public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); } }


方案五: 使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似


import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadDemo { private static Lock lock = new ReentrantLock(); private static int count = 0; private static Condition A = lock.newCondition(); private static Condition B = lock.newCondition(); private static Condition C = lock.newCondition(); static class ThreadA extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 3; i++) { while (count % 3 != 0) A.await(); // 会释放lock锁 System.out.print("A"); count++; B.signal(); // 唤醒相应线程 } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}static class ThreadB extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { while (count % 3 != 1) B.await(); System.out.print("B"); count++; C.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}static class ThreadC extends Thread { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { while (count % 3 != 2) C.await(); System.out.print("C"); count++; A.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}public static void main(String[] args) throws InterruptedException { new ThreadA().start(); new ThreadB().start(); ThreadC threadC = new ThreadC(); threadC.start(); threadC.join(); System.out.println(count); } }




【三个线程循环的按顺序打印】

    推荐阅读