题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕打印10次ABC
整体思路:该问题为三个线程的同步唤醒机制即ThreadA->ThreadB->ThreadC->ThreadA循环执行三个线程。
public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private Thread thread; public MyThreadPrinter2(String name,Object prev,Object self) { this.name=name; this.prev=prev; this.self=self; thread=new Thread(this,name); } @Override public void run() { // TODO Auto-generated method stub int count=10; while (count>0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; self.notify(); } try { prev.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { Object aObject=new Object(); Object bObject=new Object(); Object cObject=new Object(); MyThreadPrinter2 pa=new MyThreadPrinter2("A", cObject, aObject); MyThreadPrinter2 pb=new MyThreadPrinter2("B", aObject, bObject); MyThreadPrinter2 pc=new MyThreadPrinter2("c", bObject, cObject); pa.thread.start(); // try { // Thread.sleep(1); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } pb.thread.start(); // try { // Thread.sleep(10); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } pc.thread.start(); // try { // Thread.sleep(10); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } } }
运行后的打印结果为ACBACBACBACBACBACBACBACBACBACB。最后通过在start()中做延迟可以解决顺序不正确的问题。此方法用到两个锁,有些浪费资源。还有个问题就是打印后,程序还在运行。
针对以上问题,可以采用sleep方法
public class SleepExample extends Thread{ private static int currentCount=0; public SleepExample(String name) { this.setName(name); } @Override public void run() { while (currentCount<30) { switch (currentCount%3) { case 0: if ("A".equals(getName())) { printAndIncrease(); } break; case 1: if ("B".equals(getName())) { printAndIncrease(); } break; case 2: if ("C".equals(getName())) { printAndIncrease(); } break; default: break; } } } private void printAndIncrease() { // TODO Auto-generated method stub print(); increase(); } private void increase() { currentCount++; } private void print() { System.out.print(getName()); if ("C".equals(getName())) { System.out.println(); } } public static void main(String[] args) { new SleepExample("A").start(); new SleepExample("B").start(); new SleepExample("C").start(); } }
通过currentCount%3的余数控制线程打印A、B、C的顺序。也就是通过currentCount%3的余数来控制Thread.sleep()状态。
使用synchronized,wait和notify
public class PrintRunable implements Runnable{ private LetterPrinter letterPrinter=null; private char letter=' '; public PrintRunable(LetterPrinter letterPrinter,char letter) { super(); this.letterPrinter=letterPrinter; this.letter=letter; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10; i++) { synchronized (letterPrinter) { while (letter!=letterPrinter.getLetter()) { try { letterPrinter.wait();//告知被调用的线程放弃管程进入休眠直到其他线程进入相同的管程并且调用notify()/notifyAll() } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } letterPrinter.Print(); letterPrinter.nextLetter(); letterPrinter.notifyAll();//恢复相同对象中第一个调用wait()的线程 } } } }
字母打印顺序:
public class LetterPrinter { private char letter='A'; void Print(){ System.out.print(letter); if ('C'==letter) { System.out.println(); } } void nextLetter() { switch (letter) { case 'A': letter='B'; break; case 'B': letter='C'; break; case 'C': letter='A'; break; default: break; } } /** * @return the letter */ public char getLetter() { return letter; } }
public class PrintThreadExample { public static void main(String[] args) { LetterPrinter letterPrinter=new LetterPrinter(); ExecutorService service=Executors.newFixedThreadPool(3); service.execute(new PrintRunable(letterPrinter, 'A'));//开启A线程 service.execute(new PrintRunable(letterPrinter, 'B'));//开启B线程 service.execute(new PrintRunable(letterPrinter, 'C'));//开启C线程 service.shutdown();//结束程序 } }
使用Lock方法
public class ABC { private static int state=0; public static void main(String[] args) { final Lock lock=new ReentrantLock(); Thread A=new Thread(new Runnable() { public void run() { while (state<=30) { lock.lock();//get lock if (state%3==0) { System.out.print("A"); state++; } lock.unlock();//release lock } } }); Thread B=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (state<=30) { lock.lock();//get lock if (state%3==1) { System.out.print("B"); state++; } lock.unlock();//release lock } } }); Thread C=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (state<=30) { lock.lock();//get lock if (state%3==2) { System.out.print("C"); state++; } lock.unlock();//release lock } } }); A.start(); B.start(); C.start(); } }