1. 标题三个线程同时运行,依次打印ABC,一共打印10次
算法代码如下:
public class ThreadTest {private Object oa = new Object();private Object ob = new Object();private Object oc = new Object();private static final String TAG = "ThreadTest";private Runnable a = new Runnable() {@Overridepublic void run() {int count = 10;while (count > 0) {synchronized (oc) { //首先需要等待上个线程执行打印后,才能执行自己线程的打印任务。因此要获取到上个对象锁,这里是oc,并且执行oc.wait()方法//这样一旦在C线程中,oc执行了notify()方法后,才能按顺序让A线程继续执行synchronized (oa) { // 为了唤醒下一个B线程,执行oa.notify()方法,那么就需要对oa加锁Log.i(TAG, "A");count --;oa.notify();}try {oc.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}};private Runnable b = new Runnable() {@Overridepublic void run() {int count = 10;while (count > 0) {synchronized (oa) {synchronized (ob) {Log.i(TAG, "B");count --;ob.notify();}try {oa.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}};private Runnable c = new Runnable() {@Overridepublic void run() {int count = 10;while (count > 0) {synchronized (ob) {synchronized (oc) {Log.i(TAG, "C");count --;oc.notify();}try {ob.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}};public void startThread() {Thread at = new Thread(a);Thread bt = new Thread(b);Thread ct = new Thread(c);try {at.start();Thread.sleep(100); //保证第一次循环是ABC的顺序bt.start();Thread.sleep(100);ct.start();} catch (InterruptedException e) {e.printStackTrace();}}}
也可以把重复的Runnable抽象成一个,如下:
private static class PrintRunnable implements Runnable {Object prev;Object current;String name;PrintRunnable(String name, Object prev, Object current) {this.name = name;this.prev = prev;this.current = current;}@Overridepublic void run() {int count = 10;while (count > 0) {synchronized (prev) {synchronized (current) {Log.i(TAG, name);count --;current.notify();}try {prev.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}public void startThread2() {Thread ta = new Thread(new PrintRunnable("A", oc, oa));Thread tb = new Thread(new PrintRunnable("B", oa, ob));Thread tc = new Thread(new PrintRunnable("C", ob, oc));try {ta.start();Thread.sleep(100);tb.start();Thread.sleep(100);tc.start();} catch (InterruptedException e) {e.printStackTrace();}}
wait()会释放对象锁;notify()是起到唤醒等待对象锁的线程的作用,并不会马上释放锁,但是一旦同步代码块执行完毕后,就会释放对象锁。
2.生产者-消费者问题
代码如下:
/*** 生产者消费者问题*/private static final int MAX_COUNT = 10;List<String> product = new LinkedList<>();// 生产者private Runnable build = new Runnable() {@Overridepublic void run() {while (true) {synchronized (product) {while (product.size() >= MAX_COUNT) {// 如果商品已经达到最大存储量,则暂时不生产try {Log.i(TAG, Thread.currentThread().getName() + " 仓库已满");product.wait();} catch (InterruptedException e) {e.printStackTrace();}}product.add("商品");Log.i(TAG, Thread.currentThread().getName() + " 生产一个商品,当前商品存储量:" + product.size());product.notifyAll(); // 唤醒等待商品的消费者}try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}};// 消费者private Runnable consume = new Runnable() {@Overridepublic void run() {while (true) {synchronized (product) {while (product.isEmpty()) {try {Log.i(TAG, Thread.currentThread().getName() + " 仓库已空");product.wait(); // 没有商品消费,等待生产} catch (InterruptedException e) {e.printStackTrace();}}product.remove(0);Log.i(TAG, Thread.currentThread().getName() + " 消费一个商品,当前商品存储量:" + product.size());product.notifyAll(); // 通知等待生产的生产者}try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}}}};public void startThread3() {Thread buildThread1 = new Thread(build);Thread buildThread2 = new Thread(build);Thread consumeThread1 = new Thread(consume);Thread consumeThread2 = new Thread(consume);Thread consumeThread3 = new Thread(consume);buildThread1.start();consumeThread1.start();buildThread2.start();consumeThread2.start();consumeThread3.start();}
打印如下: