实现三个线程轮流执行顺序打印ABC

这道题目在多线程的面试题中可能遇到的比较多,由于最近一直在学习Java多线程编程的知识,这里做一个总结,总结的可能并不是很全面,有问题或者有更好的编程方法也欢迎大家指出。
这道题目的实现方式很多,这里就以我了解的进行一个总结。
首先,我们看一下题目:
有三个线程A、B、C,采用多线程的方式使三个线程轮流执行顺序打印ABC 10次,结果如下:

通过wait/notify实现

package test.printThread.test2;

/** * * <p>Title: PrintABCUsingWaitNotify.java</p> * <p>Description: * ABCABCABCABCABCABCABCABCABCABC * <p> * @author tianqb * @mail tqb820965236@163.com * @date 2019年6月7日下午5:29:39 * @version 1.0 * */
public class PrintABCUsingWaitNotify {
	private int times;// 打印的次数
	private int state = 0;// 打印的状态
	private Object objectA = new Object();
	private Object objectB = new Object();
	private Object objectC = new Object();
	
	public PrintABCUsingWaitNotify(int times) {
		super();
		this.times = times;
	}
	
	public void printA(){
		print("A", 0, objectA, objectB);
	}
	
	public void printB(){
		print("B", 1, objectB, objectC);
	}
	
	public void printC(){
		print("C", 2, objectC, objectA);
	}
	
	public void print(String name, int targetState, Object curr, Object next){
		for (int i = 0; i < times;) {
			synchronized (curr) {
				while(state % 3 != targetState){
					try {
						curr.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				i++;
				state++;
				System.out.print(name);
				synchronized (next) {
					next.notify();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		PrintABCUsingWaitNotify p = new PrintABCUsingWaitNotify(10);
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printA();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printB();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printC();
			}
		}).start();
	}
}

这里对题目进行一个扩展,顺序执行打印AAAAAAAAAABBBBBBBBBBCCCCCCCCCC

package test.printThread.test3;

/** * * <p> * Title: PrintABCUsingWaitNotify.java * </p> * <p> * Description: * AAAAAAAAAABBBBBBBBBBCCCCCCCCCC * <p> * * @author tianqb * @mail tqb820965236@163.com * @date 2019年6月7日下午5:29:58 * @version 1.0 * */
public class PrintABCUsingWaitNotify {
	private int times;// 打印的次数
	private int state = 0;// 打印的状态
	private Object objectA = new Object();
	private Object objectB = new Object();
	private Object objectC = new Object();

	public PrintABCUsingWaitNotify(int times) {
		super();
		this.times = times;
	}

	public void printA() {
		print("A", 0, objectA, objectB);
	}

	public void printB() {
		print("B", 1, objectB, objectC);
	}

	public void printC() {
		print("C", 2, objectC, objectA);
	}

	public void print(String name, int targetState, Object curr, Object next) {
		synchronized (curr) {
			while (state % 3 != targetState) {
				try {
					curr.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			state++;
			for (int i = 0; i < times; i++) {
				System.out.print(name);
			}
			synchronized (next) {
				next.notify();
			}
		}
	}

	public static void main(String[] args) {
		PrintABCUsingWaitNotify p = new PrintABCUsingWaitNotify(10);
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printC();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printB();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				p.printA();
			}
		}).start();
	}
}

通过join()方法实现(这种方法若题目要求只打印ABC一次,可以采用,若多次打印ABC,调用的就不是start()方法了,而是run()方法,因为start()方法在调用一次之后线程状态发生改变,再次调用会抛出IllegalThreadStateException,源码如下)

public synchronized void start() {
        /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */
            }
        }
}

实现代码:

package test.printThread.test4;

public class PrintABCUsingJoin {
	public static void main(String[] args) {
		Thread a  = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.print("A");
			}
		});
		Thread b  = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					a.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.print("B");
			}
		});
		Thread c  = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					b.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.print("C");
			}
		});
		
		for (int i = 0; i < 10; i++) {
				a.run();
				b.run();
				c.run();
		}
	}
}

通过isAlive方法实现(限制如join方法)

package test.printThread.test5;

public class PrintABCUsingIsAlive {
	public static void main(String[] args) throws InterruptedException {
		Thread A = new Thread(() -> {
			System.out.print("A");
		});
		Thread B = new Thread(() -> {
			System.out.print("B");
		});
		Thread C = new Thread(() -> {
			System.out.print("C");
		});

		int i = 10;
		while (i > 0) {
			A.run();
			while (A.isAlive()) {
			}
			B.run();
			while (B.isAlive()) {
			}
			C.run();
			while (C.isAlive()) {
			}

			i--;
		}
	}
}

使用Lock和Condition对象实现(等待/唤醒)

package chapter4.locks.printABC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrintABC {
	private int times;
	private int count = 0;
	
	private Lock lock = new ReentrantLock();
	private Condition c1 = lock.newCondition();
	private Condition c2 = lock.newCondition();
	private Condition c3 = lock.newCondition();
	
	public PrintABC(int times) {
		super();
		this.times = times;
	}
	
	public void print(int target, Condition curr, Condition next){
		for (int i = 0; i < times;) {
			try {
				lock.lock();
				while(count % 3 != target){
					curr.await();
				}
				System.out.print(Thread.currentThread().getName());
				count++;
				i++;
				next.signalAll();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}
	
	public void printA(){
		print(0, c1, c2);
	};
	
	public void printB(){
		print(1, c2, c3);
	};
	
	public void printC(){
		print(2, c3, c1);
	};
	
}
package chapter4.locks.printABC;

public class Run {
	public static void main(String[] args) {
		PrintABC p = new PrintABC(10);
		
		new Thread(() -> {
			p.printA();
		},"A").start();
		
		new Thread(() -> {
			p.printB();
		},"B").start();
		
		new Thread(() -> {
			p.printC();
		},"C").start();
	}
}

目前了解的就这么些了,之后学习到新的方法继续更新。

全部评论

相关推荐

03-26 22:55
门头沟学院 Java
烤冷面在迎接:河南byd,应该就是郑大了。不过24届计算机是特殊情况,那年除了九✌和强2,以及两三个关系够硬的双非,其他的都是炮灰,感觉是十几年来互联网行业最烂的一年,如果想了解最新的就业情况,得找现在的大四。
点赞 评论 收藏
分享
嘀哩咕噜说啥呢:27届,这简历,强的逆天,大厂实习随便冲,面经多少看点,hot100刷完,大厂随便挑了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务