题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…
此乃多线程笔面试常考题目之一,下面提供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();
}
}
方法3、用线程池、Lock锁和condition(Object 监视器方法的使用)组合使用实现:
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();
}
}
}
}
方法3.5: 用线程池、synchronized关键字和Object 监视器方法组合实现(实现跟第3种大同小异)
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();
}
}
}
}
}
}
}
第4种: 不用线程池,synchronized关键字和Object 监视器方法组合实现(Lock和Condition差不多就不写了):
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();
}
}
}
}
}
}
}
}
二、Linux C
#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;
}