【机试】华为2014校招机试:多线程循环打印十次ABC

 题目:有三个线程分别打印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();
    }
}


方法2:使用管道流在进程间传递消息控制打印次序

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;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
108题中有部分题目重合,因此么有收录在压缩文件中。 华为机试 ├─001 字符串最后一个单词长度 │ └─Source ├─002 计算字符个数 │ └─Source ├─003 明明的随机数 │ └─Source ├─004 字符串分隔 │ └─Source ├─005 进制转换 │ └─Source ├─006 质数因子 │ └─Source ├─007 取近似值 │ └─Source ├─008 合并表记录 │ └─Source ├─009 提取不重复的整数 │ └─Source ├─010 字符个数统计 │ └─Source ├─011 数字颠倒 │ └─Source ├─012 字符串反转 │ └─Source ├─013 句子逆序 │ └─Source ├─014 字典序排序 │ └─Source ├─015 求int型正整数在内存中存储是1的个数 │ └─Source ├─016 购物单 │ ├─Debug │ ├─Source │ │ └─Debug │ ├─Source - 时间优先 │ │ └─Debug │ └─Source - 空间优先 │ ├─Debug │ └─Release ├─017 坐标移动 ├─018 识别IP地址分类统计 │ └─Source │ └─Debug ├─019 错误记录 ├─020 密码验证合格程序 ├─021 密码破解 ├─023 删除字符串中出现数最少字符 │ └─Source │ └─Debug ├─024 合唱队 │ └─Source │ ├─Debug │ └─Release ├─025 数据分类处理 │ └─Source │ └─Debug ├─026 查找兄弟单词 │ └─Source │ └─Debug ├─027 素数伴侣 │ └─Source │ └─Debug ├─028 字符串合并处理 │ └─Source │ └─Debug ├─030 密码截取(查找最长回文字符串) ├─031 蛇形矩阵 │ └─Source │ └─Debug ├─033 判断IP是否属于同一子网 │ └─Source │ └─Debug ├─034 称砝码 │ └─Source │ └─Debug ├─035 学英语 │ └─Source │ └─Debug ├─036 迷宫问题 │ └─Source │ └─Debug ├─037 数独问题 │ └─Debug ├─038 名字漂亮度 │ └─Source │ └─Debug ├─039 字符串截取 │ └─Source │ └─Debug ├─040 单链表删除数据 │ └─Source │ └─Debug ├─041 多线程 │ └─Source │ ├─Backup │ ├─Debug │ │ └─041.tlog │ └─Release │ └─041.tlog ├─042 表达式计算 │ └─Source │ └─Debug ├─043 计算字符串距离 │ └─Source │ └─Debug ├─044 杨辉三角形变形 ├─046 挑7 ├─047 完全数 │ └─Debug ├─048 高精度加法 ├─049 输出n个数中最小的k个 │ └─Debug ├─050 找出字符串只出现一的字符 │ └─Debug ├─051 组成一个偶数最接近的2个质数 │ └─Debug ├─052 M个苹果放入N个盘子 ├─053 查找整数二进制中1的个数 ├─054 DNA子串 ├─055 MP3光标位置 │ └─Source │ └─Debug ├─056 查找2个字符串最大相同子串 │ └─Debug ├─057 配置文件恢复 │ └─Source │ └─Debug ├─058 24点计算 │ └─Debug ├─059 成绩排序 ├─060 矩阵相乘 ├─061 矩阵乘法数计算 ├─062 字符串通配符 │ └─Debug ├─066 命令行解析 │ └─Source │ └─Debug ├─067 最大相同子串长度 │ └─Debug ├─068 火车编号进站 │ └─Debug ├─072 数组合并 ├─074 埃及分数 │ └─Source │ └─Debug ├─076 密码截取 │ └─Source ├─077 求最大连续bit数 ├─078 密码强度 ├─079 扑克牌大小 │ └─Source │ └─Debug ├─081 合法IP ├─082 棋盘格子走法 ├─083 在字符串中找出连续最长数字串 ├─084 int数组分组,两组和相等 │ └─Source │ └─Debug ├─086 人民币转换 │ └─Source │ └─Debug ├─087 表示数字 ├─090 自动售货系统 │ └─Source │ └─Debug └─091 24点输出 └─Debug
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值