此乃多线程笔面试常考题目之一,下面提供Java和Linux C两种解法
一、Java
方法1:使用wait()、notify()控制打印次序
public class Test { public static Object a = new Object(); public static Object b = new Object(); public static Object c = new Object(); public class Runner1 implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { synchronized (a) { // System.out.println("a is locked by t1"); synchronized (b) { // System.out.println("b is locked by t1"); System.out.print("A"); b.notify(); // System.out.println("t1 notify b"); } if (i < 9) { a.wait(); } } } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Runner2 implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { synchronized (b) { // System.out.println("b is locked by t2"); synchronized (c) { // System.out.println("c is locked by t2"); System.out.print("B"); c.notify(); // System.out.println("t2 notify c"); } if (i < 9) { b.wait(); } } } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Runner3 implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { synchronized (c) { // System.out.println("c is locked by t3"); synchronized (a) { // System.out.println("a is locked by t3"); System.out.print("C"); a.notify(); // System.out.println("t3 notify a"); } if (i < 9) { c.wait(); } } } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Test t = new Test(); Thread t1 = new Thread(t.new Runner1(), "t1"); Thread t2 = new Thread(t.new Runner2(), "t2"); Thread t3 = new Thread(t.new Runner3(), "t3"); t1.start(); try { Thread.sleep(1); } catch (InterruptedException e1) { e1.printStackTrace(); } t2.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t3.start(); } }
import java.io.*; class RunnerA implements Runnable{ DataInputStream disA=null; DataOutputStream dosA=null; public RunnerA(PipedInputStream pisA,PipedOutputStream posA){ disA=new DataInputStream(pisA); dosA=new DataOutputStream(posA); } public void run(){ try{ for(int i=0;i<10;i++){ if(i==0){ System.out.print("A"); dosA.writeChar('A'); }else if(i==9){ char c=disA.readChar(); System.out.print("A"); dosA.writeChar('O'); }else{ char c=disA.readChar(); System.out.print("A"); dosA.writeChar('A'); } } }catch(IOException e){ e.printStackTrace(); } } } class RunnerB implements Runnable{ DataInputStream disB=null; DataOutputStream dosB=null; public RunnerB(PipedInputStream pisB,PipedOutputStream posB){ disB=new DataInputStream(pisB); dosB=new DataOutputStream(posB); } public void run(){ try{ char c=disB.readChar(); while(true){ if(c=='O'){ System.out.print("B"); dosB.writeChar('O'); break; } if(c=='A'){ System.out.print("B"); dosB.writeChar('B'); c=disB.readChar(); } } }catch(IOException e){ e.printStackTrace(); } } } class RunnerC implements Runnable{ DataInputStream disC=null; DataOutputStream dosC=null; public RunnerC(PipedInputStream pisC,PipedOutputStream posC){ disC=new DataInputStream(pisC); dosC=new DataOutputStream(posC); } public void run(){ try{ char c=disC.readChar(); while(true){ if(c=='O'){ System.out.print("C"); break; } if(c=='B'){ System.out.print("C"); dosC.writeChar('C'); c=disC.readChar(); } } }catch(IOException e){ e.printStackTrace(); } } } public class Test{ public static void main(String[] args){ PipedOutputStream posA=new PipedOutputStream(); PipedInputStream pisA=new PipedInputStream(); PipedOutputStream posB=new PipedOutputStream(); PipedInputStream pisB=new PipedInputStream(); PipedOutputStream posC=new PipedOutputStream(); PipedInputStream pisC=new PipedInputStream(); try{ pisA.connect(posC); pisB.connect(posA); pisC.connect(posB); }catch(IOException e){ e.printStackTrace(); } Thread ta=new Thread(new RunnerA(pisA,posA),"ta"); Thread tb=new Thread(new RunnerB(pisB,posB),"tb"); Thread tc=new Thread(new RunnerC(pisC,posC),"tc"); ta.start(); tb.start(); tc.start(); } }
package multithread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestABCThread { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private int count; public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); TestABCThread abc = new TestABCThread(); for (int i = 0; i < 10; i++) { executorService.execute(abc.new Run("AAAAAAAAAAAAAAAA", 1)); executorService.execute(abc.new Run("BBBBBBBBBBBBBBBBB", 2)); executorService.execute(abc.new Run("CCCCCCCCCCCCCCcCC", 3)); } executorService.shutdown(); } class Run implements Runnable { private String _name = ""; private int _threadNum; public Run(String name, int threadNum) { _name = name; _threadNum = threadNum; } @Override public void run() { lock.lock(); try { while (true) { if (count % 3 == _threadNum - 1) { System.out.println("Thread-Name:" + _name); count++; condition.signalAll(); break; } else { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } } finally { lock.unlock(); } } } }
package multithread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestABCThread2 { private Object lock = new Object(); private int count; public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); TestABCThread2 abc = new TestABCThread2(); for (int i = 0; i < 10; i++) { executorService.execute(abc.new Run("AAAAAAAAAAAAAAAA", 1)); executorService.execute(abc.new Run("BBBBBBBBBBBBBBBBB", 2)); executorService.execute(abc.new Run("CCCCCCCCCCCCCCcCC", 3)); } executorService.shutdown(); } class Run implements Runnable { private String _name = ""; private int _threadNum; public Run(String name, int threadNum) { _name = name; _threadNum = threadNum; } @Override public void run() { synchronized (lock) { while (true) { if (count % 3 == _threadNum - 1) { System.out.println("Thread-Name:" + _name); count++; lock.notifyAll(); break; } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } }
package multithread; public class TestABCThread3 { private Object lock = new Object(); private int count; public static void main(String[] args) { TestABCThread3 abc = new TestABCThread3(); new Thread(abc.new Run("AAAAAAAAAAAAAAAA", 1)).start(); new Thread(abc.new Run("BBBBBBBBBBBBBBBBB", 2)).start(); new Thread(abc.new Run("CCCCCCCCCCCCCCcCC", 3)).start(); } class Run implements Runnable { private String _name = ""; private int _threadNum; public Run(String name, int threadNum) { _name = name; _threadNum = threadNum; } @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (lock) { while (true) { if (count % 3 == _threadNum - 1) { System.out.println("Count:" + i + ",Thread-Name:" + _name); count++; lock.notifyAll(); break; } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } } }
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <string.h> //#define DEBUG 1 #define NUM 3 int n=0; pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;//互斥量 pthread_cond_t qready=PTHREAD_COND_INITIALIZER;//条件变量 void * thread_func(void *arg) { int param=(int)arg; char c='A'+param; int ret,i=0; for (; i < 10; i++) { pthread_mutex_lock(&mylock); while (param != n) //刚运行时,n = 0, param = 0,条件不成立,所以直接打印A { #ifdef DEBUG printf("thread %d waiting\n", param); #endif ret = pthread_cond_wait(&qready, &mylock); if (ret == 0) { #ifdef DEBUG printf("thread %d wait success\n", param); #endif } else { #ifdef DEBUG printf("thread %d wait failed:%s\n", param, strerror(ret)); #endif } } // printf("%d ",param+1); printf("%c ",c); //打印A后 n=(n+1)%NUM; //n变成了1,对线程2会产出影响!!!! pthread_mutex_unlock(&mylock); //会唤醒所有的线程,因为当这个线程完后会等pthread_cond_wait()执行两次后才能退出while (param != n) pthread_cond_broadcast(&qready); } return (void *)0; } #if 0 //假设为线程2 void * thread_func(void *arg)//传入值1 { int param=(int)arg; char c='A'+param; int ret,i=0; for (; i < 10; i++) { pthread_mutex_lock(&mylock); while (param != n) //和线程1同时执行,所以刚开始时条件满足 { #ifdef DEBUG printf("thread %d waiting\n", param); #endif //执行到此时,等待线程1发送信号,当线程1的A打印完后,n的值也变成了1,条件就不成立了 ret = pthread_cond_wait(&qready, &mylock); if (ret == 0) { #ifdef DEBUG printf("thread %d wait success\n", param); #endif } else { #ifdef DEBUG printf("thread %d wait failed:%s\n", param, strerror(ret)); #endif } } // printf("%d ",param+1); printf("%c ",c); //此时打印值B n=(n+1)%NUM; //对打印C的线程3产生影响!!! pthread_mutex_unlock(&mylock); pthread_cond_broadcast(&qready); } return (void *)0; } #endif int main(int argc, char** argv) { int i=0,err; pthread_t tid[NUM]; void *tret; for(;i<NUM;i++) { err=pthread_create(&tid[i],NULL,thread_func,(void *)i); if(err!=0) { printf("thread_create error:%s\n",strerror(err)); exit(-1); } } for (i = 0; i < NUM; i++) { err = pthread_join(tid[i], &tret); if (err != 0) { printf("can not join with thread %d:%s\n", i,strerror(err)); exit(-1); } } printf("\n"); return 0; }