1、生产者消费者问题
wait() 必须在synchronized 函数或者代码块里面
wait()会让已经获得synchronized 函数或者代码块控制权的Thread暂时休息,并且丧失控制权
这个时候,由于该线程丧失控制权并且进入等待,其他线程就能取得控制权,并且在适当情况下调用notifyAll()来唤醒wait()的线程。
需要注意的是,被唤醒的线程由于已经丧失了控制权,所以需要等待唤醒它的线程结束操作,从而才能重新获得控制权。
所以wait()的确是马上让当前线程丧失控制权,其他的线程可以乘虚而入。
此例中:
当产品仓库满的时候,生产者线程需要wait(),从而放弃对产品仓库的控制。
这个时候消费者线程就可以进来了而取得仓库的控制权。一旦消费者消费了产品,那么仓库就不满了。
这个时候消费者线程就要notifyAll()生产者线程,让等待的生产者线程唤醒。
但是生产者被唤醒后不能马上进行生产,因为它在wait()的时候已经丧失了对仓库的控制权,所以就需要等待消费者线程结束操作,
才能重新取得仓库的控制权,再进行生产。
所以特别注意的是,notifyAll()并不是让当前线程马上让出控制权,而只是让其他wait()当中的线程唤醒而已,
所以对不起,尽管我唤醒你,可你必须还是要等我用完仓库才能进来。这点必须清楚。
相反,仓库如果空的时候,消费者线程就会wait(),然后等待生产者线程来生产产品,生产者进程乘虚而入后,让生产者线程生产产品
并且唤醒消费者线程。这个情况跟上面就类似了。
package threadProblems;
public class ProducerConsumer {
public static void main(String args[]) {
Basket basket = new Basket();
Producer producer = new Producer(basket);
Consumer comsumer = new Consumer(basket);
new Thread(producer).start();
new Thread(comsumer).start();
}
}
class Producer implements Runnable {
Basket basket;
public Producer(Basket b) {
this.basket = b;
}
public void run() {
for (int i = 0; i < 20; i++) {
basket.push(i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
Basket basket;
public Consumer(Basket b) {
this.basket = b;
}
public void run() {
for (int i = 0; i < 20; i++) {
int j = basket.pop();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Basket {
int[] basket = new int[6];
int index = 0;
public synchronized int pop() {
while (index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
System.out.println("编号: " + basket[index] + " 被消费");
return basket[index];
}
public synchronized void push(int i) {
while (index == 6) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
basket[index] = i;
System.out.println("编号: " + i + " 被生产");
index++;
}
}
2、造一个死锁的程序
package threadProblems;
public class TestDeadLock implements Runnable {
public int flag = 1;
public Object o1;
public Object o2;
public void run() {
if (flag == 1) {
synchronized (o1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println("1");
}
}
}
if (flag == 2) {
synchronized (o2) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("2");
}
}
}
}
public static void main(String args[]) {
TestDeadLock t1 = new TestDeadLock();
TestDeadLock t2 = new TestDeadLock();
t1.flag = 1;
t2.flag = 2;
Object o1 = new Object();
Object o2 = new Object();
t1.o1 = o1;
t1.o2 = o2;
t2.o1 = o1;
t2.o2 = o2;
new Thread(t1).start();
new Thread(t2).start();
}
}
3、使用三个线程打印分别打印A、B、C 10次 保持ABC的顺序不变
package threadProblems;
public class PrintABCtenTimes {
public static int count = 0;
public static void main(String args[]) {
Object lockObj = new Object();
Printer pa = new Printer(0, lockObj, "A");
Printer pb = new Printer(1, lockObj, "B");
Printer pc = new Printer(2, lockObj, "C");
new Thread(pa).start();
new Thread(pb).start();
new Thread(pc).start();
}
}
class Printer implements Runnable {
int i;
String s;
Object lockObj;
public Printer(int i, Object lockObj, String s) {
this.i = i;
this.lockObj = lockObj;
this.s = s;
}
public void run() {
for (int j = 0; j < 10; j++) {
synchronized (lockObj) {
while (true) {
if (PrintABCtenTimes.count % 3 == i) {
System.out.print(s);
PrintABCtenTimes.count++;
lockObj.notifyAll();
break;
} else {
try {
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}