疑问
- 为什么wait()要放到while循环里?
外界的某种变量条件发生改变,当前线程被唤醒,但此时被唤醒有可能不是满足我当前线程条件而进行之后的逻辑。假设有这样一个情景,当前线程被处于阻塞,某一线程调用notifyall(),当时可能满足条件变量,但是其中被唤醒的另一个线程又改变了条件变量,然而等到当前线程被唤醒,但并不满足逻辑所需,所以此时需要再次对wait()条件进行判断,是否此时满足逻辑,否则继续wait()。
同步队列的方式
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
/**
* BlockingQueue
* 一台机器有3个任务,1、制作吐司 2、上黄油 3、 途果酱
* @author liqiushi
*
*/
/**
* 吐司
*
* @author liqiushi
*
*/
class Toast{
public enum Status {
DRY, BUTTERED, JAMMED
}
private final int id;
private Status status = Status.DRY;
public Toast(int id) {
this.id = id;
}
public Status getStatus() {
return status;
}
public void butter() {
status = Status.BUTTERED;
}
public void jam() {
status = Status.JAMMED;
}
public int getId() {
return id;
}
public String toString() {
return "toast " + id + ":" + status;
}
}
class ToastBlockQueue extends LinkedBlockingDeque { }
/**
* 制作吐司工
*
* @author liqiushi
*
*/
class Toaster implements Runnable {
private ToastBlockQueue toastBlockQueue;
private int count = 0;
public Toaster(ToastBlockQueue toastBlockQueue){
this.toastBlockQueue = toastBlockQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
Toast toast = new Toast(count++);
System.out.println(toast);
toastBlockQueue.put(toast);
}
} catch (Exception e) {
System.out.println("Toaster interrupted");
}
System.out.println("Toaster off");
}
}
/**
* 黄油线程
*
* @author liqiushi
*
*/
class Butter implements Runnable {
private ToastBlockQueue toastBlockQueue;
private ToastBlockQueue butteredQueue;
public Butter(ToastBlockQueue toastBlockQueue, ToastBlockQueue butteredQueue) {
this.toastBlockQueue = toastBlockQueue;
this.butteredQueue = butteredQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
Toast toast = toastBlockQueue.take();
toast.butter();
System.out.println(toast);
butteredQueue.put(toast);
}
} catch (Exception e) {
System.out.println("Butter interrupted");
}
System.out.println("Butter off");
}
}
class Jamer implements Runnable {
private ToastBlockQueue butteredQueue;
private ToastBlockQueue jamedQueue;
public Jamer(ToastBlockQueue butteredQueue, ToastBlockQueue jamedQueue) {
this.butteredQueue = butteredQueue;
this.jamedQueue = jamedQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
Toast toast = butteredQueue.take();
toast.jam();
System.out.println(toast);
jamedQueue.put(toast);
}
} catch (Exception e) {
System.out.println("Jamer interrupted");
}
System.out.println("Jamer off");
}
}
class Eater implements Runnable {
private ToastBlockQueue jamedQueue;
private int id = 0;
public Eater(ToastBlockQueue jamedQueue) {
this.jamedQueue = jamedQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
Toast toast = jamedQueue.take();
if (toast.getId() != id++|| toast.getStatus() != Toast.Status.JAMMED) {
System.out.println("err");
System.exit(1);
} else {
System.out.println("eat!");
}
}
} catch (Exception e) {
System.out.println("eater interrupted");
}
System.out.println("eater off");
}
}
/**
* test
* @author liqiushi
*
*/
public class BlockQueue {
public static void main(String[] args) throws InterruptedException {
ToastBlockQueue dryQueue = new ToastBlockQueue();
ToastBlockQueue butterQueue = new ToastBlockQueue();
ToastBlockQueue jamQueue = new ToastBlockQueue();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Toaster(dryQueue));
executorService.execute(new Butter(dryQueue, butterQueue));
executorService.execute(new Jamer(butterQueue, jamQueue));
TimeUnit.SECONDS.sleep(2);
executorService.shutdownNow();
}
}
下面是java编程思想后面的一道练习
package ThreadCollaboration;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
class Toast {
public enum Status {
DRY, BUTTERED, JAMMED, READY {
public String toString() {
return BUTTERED.toString() + " & " + JAMMED.toString();
}
}
}
private Status status = Status.DRY;
private final int id;
public Toast(int idn) {
id = idn;
}
public void butter() {
status = (status == Status.DRY) ? Status.BUTTERED : Status.READY;
}
public void jam() {
status = (status == Status.DRY) ? Status.JAMMED : Status.READY;
}
public Status getStatus() {
return status;
}
public int getId() {
return id;
}
public String toString() {
return "Toast " + id + ": " + status;
}
}
class ToastQueue extends LinkedBlockingQueue {
}
class Toaster implements Runnable {
private ToastQueue toastQueue;
private int count;
private Random rand = new Random(47);
public Toaster(ToastQueue tq) {
toastQueue = tq;
}
public void run() {
try {
while (!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(500));
// Make toast
Toast t = new Toast(count++);
System.out.println(t);
// Insert into queue
toastQueue.put(t);
}
} catch (InterruptedException e) {
System.out.println("Toaster interrupted");
}
System.out.println("Toaster off");
}
}
// Apply butter to toast:
class Butterer implements Runnable {
private ToastQueue inQueue, butteredQueue;
public Butterer(ToastQueue in, ToastQueue buttered) {
inQueue = in;
butteredQueue = buttered;
}
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next piece of toast is available:
Toast t = inQueue.take();
t.butter();
System.out.println(t);
butteredQueue.put(t);
}
} catch (InterruptedException e) {
System.out.println("Butterer interrupted");
}
System.out.println("Butterer off");
}
}
// Apply jam to toast:
class Jammer implements Runnable {
private ToastQueue inQueue, jammedQueue;
public Jammer(ToastQueue in, ToastQueue jammed) {
inQueue = in;
jammedQueue = jammed;
}
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next piece of toast is available:
Toast t = inQueue.take();
t.jam();
System.out.println(t);
jammedQueue.put(t);
}
} catch (InterruptedException e) {
System.out.println("Jammer interrupted");
}
System.out.println("Jammer off");
}
}
// Consume the toast:
class Eater implements Runnable {
private ToastQueue finishedQueue;
public Eater(ToastQueue finished) {
finishedQueue = finished;
}
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next piece of toast is available:
Toast t = finishedQueue.take();
// Verify that all pieces are ready for consumption:
if (t.getStatus() != Toast.Status.READY) {
System.out.println(">>>> Error: " + t);
System.exit(1);
} else
System.out.println("Chomp! " + t);
}
} catch (InterruptedException e) {
System.out.println("Eater interrupted");
}
System.out.println("Eater off");
}
}
// Outputs alternate inputs on alternate channels:
// 将dry分开成两个工作,一个黄油,一个酱
class Alternator implements Runnable {
private ToastQueue inQueue, out1Queue, out2Queue;
private boolean outTo2; // control alternation
public Alternator(ToastQueue in, ToastQueue out1, ToastQueue out2) {
inQueue = in;
out1Queue = out1;
out2Queue = out2;
}
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next piece of toast is available:
Toast t = inQueue.take();
if (!outTo2)
out1Queue.put(t);
else
out2Queue.put(t);
outTo2 = !outTo2; // change state for next time
}
} catch (InterruptedException e) {
System.out.println("Alternator interrupted");
}
System.out.println("Alternator off");
}
}
// Accepts toasts on either channel, and relays them on to
// a "single" successor
// 合并两个工作,如果是黄油就进行涂酱,反之,(异步)如果是ready就进入完成队列
class Merger implements Runnable {
private ToastQueue in1Queue, in2Queue, toBeButteredQueue, toBeJammedQueue,
finishedQueue;
public Merger(ToastQueue in1, ToastQueue in2, ToastQueue toBeButtered,
ToastQueue toBeJammed, ToastQueue finished) {
in1Queue = in1;
in2Queue = in2;
toBeButteredQueue = toBeButtered;
toBeJammedQueue = toBeJammed;
finishedQueue = finished;
}
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next piece of toast is available:
Toast t = null;
// 数据既可以来自黄油队列,也可以来自酱队列
// 所以不用无限期的等待
while (t == null) {
t = in1Queue.poll(50, TimeUnit.MILLISECONDS);
if (t != null)
break;
t = in2Queue.poll(50, TimeUnit.MILLISECONDS);
}
// Relay toast onto the proper queue
switch (t.getStatus()) {
case BUTTERED:
toBeJammedQueue.put(t);
break;
case JAMMED:
toBeButteredQueue.put(t);
break;
default:
finishedQueue.put(t);
}
}
} catch (InterruptedException e) {
System.out.println("Merger interrupted");
}
System.out.println("Merger off");
}
}
public class BlockQueue {
public static void main(String[] args) throws Exception {
ToastQueue dryQueue = new ToastQueue(), butteredQueue = new ToastQueue(), toBeButteredQueue = new ToastQueue(), jammedQueue = new ToastQueue(), toBeJammedQueue = new ToastQueue(), finishedQueue = new ToastQueue();
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Toaster(dryQueue));
exec.execute(new Alternator(dryQueue, toBeButteredQueue,
toBeJammedQueue));
exec.execute(new Butterer(toBeButteredQueue, butteredQueue));
exec.execute(new Jammer(toBeJammedQueue, jammedQueue));
exec.execute(new Merger(butteredQueue, jammedQueue, toBeButteredQueue,
toBeJammedQueue, finishedQueue));
exec.execute(new Eater(finishedQueue));
TimeUnit.SECONDS.sleep(5);
exec.shutdownNow();
}
}
//dryQueue:制作的干吐司
//toBeButteredQueue:将要被涂黄油的吐司
//toBeJammedQueue将要被涂酱的吐司
//butteredQueue、jammedQueue已经被涂了的
//Merger 整合工作,如果是黄油就进行涂酱,反之,(异步)如果是ready就进入完成队列
管道实现
//Todo
死锁
互斥条件。进程对所分配到的资源进行排他性使用,即在一段时间内,某资源只能被一个进程占用。如果此时还有其他进程请求该资源,则请求进程只能等待,直至占有该资源的进程用毕释放。
请求和保持条件。进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己以获得的资源保持不放。
不可抢占条件。进程已获得的资源在未使用完之前不能被抢占,只能在进程使用完时由自己释放。
循环等待条件。在发生死锁时,必然存在一个进程—资源的循环链,即进程集合{P0,P1,P2,P3,...,Pn}中的P0正在等待P1占用的资源,P1正在等待P2占用的资源,... ... ,Pn正在等待已被P0占用的资源。