題目:有三個線程分別打印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(); } }