线程间的协作

疑问

  • 为什么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占用的资源。

你可能感兴趣的:(线程间的协作)