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() {
@Override
public 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() {
@Override
public 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() {
@Override
public 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;
}
@Override
public 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() {
@Override
public 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() {
@Override
public 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();
}
打印如下: