这是个经典的例子,所以必会。

1、使用wait和signalAll

仓库类:

/**
 * 仓库有两个方法,加和减
 */
public class StoreManager {
    private static final int MAX_NUM = 100;// 仓库最大容量
    private int currentNum;

    public StoreManager(int n) {
        this.currentNum = n;
    }

    public synchronized void addProduct(int amount) {
        while (currentNum + amount > MAX_NUM) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        currentNum += amount;
        System.out.println("生产了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
        notifyAll();
    }

    public synchronized void takeProduct(int amount) {
        while (currentNum < amount) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        currentNum -= amount;
        System.out.println("消费了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
        notifyAll();
    }
}

生产者线程:

public class Producer implements Runnable {
    private int amount;
    private StoreManager sm;

    public Producer(int a, StoreManager sm) {
        this.amount = a;
        this.sm = sm;
    }

    @Override
    public void run() {
        sm.addProduct(amount);
    }

}

消费者线程:

public class Consumer implements Runnable {
    private int amount;
    private StoreManager sm;

    public Consumer(int a, StoreManager sm) {
        this.amount = a;
        this.sm = sm;
    }

    @Override
    public void run() {
        sm.takeProduct(amount);
    }

}

测试

public class Test {
    public static void main(String[] args) {
        StoreManager sm = new StoreManager(0);
        for (int i = 0; i < 3; i++) {
            int a = (int) (Math.random() * 20)+1;
            Thread t = new Thread(new Consumer(a, sm));
            t.start();
        }

        for (int i = 0; i < 5; i++) {
            int a = (int) (Math.random() * 20)+1;
            Thread t = new Thread(new Producer(a, sm));
            t.start();
        }

    }
}

结果

加入生产者少于消费者,则线程会挂起,因为这里使用了有限的循环,实际可能是无限的。

生产了:1个,当前容量有:1个
生产了:16个,当前容量有:17个
生产了:18个,当前容量有:35个
生产了:14个,当前容量有:49个
消费了:7个,当前容量有:42个
消费了:14个,当前容量有:28个
消费了:9个,当前容量有:19个
生产了:9个,当前容量有:28个

2、使用BlockingQueue

仓库类

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class StoreManager {
    private BlockingQueue<Integer> bq;

    public StoreManager() {
        bq = new LinkedBlockingQueue<>();
    }

    public BlockingQueue<Integer> getBlockQueue() {
        return bq;
    }
}

生产者

public class Producer implements Runnable {
    private int number;
    private final BlockingQueue<Integer> bq;

    public Producer(int n, BlockingQueue<Integer> bq) {
        this.number = n;
        this.bq = bq;
    }

    @Override
    public void run() {
        try {
            bq.put(number);
            // System.out.println("生产了数字:" + number);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

消费者

public class Consumer implements Runnable {
    private final BlockingQueue<Integer> bq;

    public Consumer(BlockingQueue<Integer> bq) {
        this.bq = bq;
    }

    @Override
    public void run() {
        try {
            System.out.println("消费了数字:" + bq.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

测试

public class Test {
    public static void main(String[] args) {
        StoreManager sm = new StoreManager();

        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(new Consumer(sm.getBlockQueue()));
            t.start();
        }
        for (int i = 0; i < 5; i++) {
            int n = (int) (Math.random() * 100) + 1;
            Thread t = new Thread(new Producer(n, sm.getBlockQueue()));
            t.start();
        }
    }
}

结果

由于输出和bq.put()可能会被拆分,所以就不打印了。

另外:BlockingQueue是一个一个生产消费的。

消费了数字:60
消费了数字:69
消费了数字:59
消费了数字:4
消费了数字:19

3、使用ReentrantLock和Condition

仓库类:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class StoreManager {
    private static final int MAX_NUM = 100;// 仓库最大容量
    private int currentNum;
    private ReentrantLock lock;
    private Condition condition;

    public StoreManager(int n) {
        this.currentNum = n;
        lock = new ReentrantLock();
        condition = lock.newCondition();
    }

    public void addProduct(int amount) {
        lock.lock();
        try {
            while (currentNum + amount > MAX_NUM) {
                System.out.println("仓库满了...");
                condition.await();
            }
            currentNum += amount;
            System.out.println("生产了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void takeProduct(int amount) {
        lock.lock();
        try {
            while (currentNum < amount) {
                System.out.println("仓库数量不够,不能取...");
                condition.await();
            }
            currentNum -= amount;
            System.out.println("消费了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

生产者

public class Producer implements Runnable {
    private int amount;
    private StoreManager sm;

    public Producer(int a, StoreManager sm) {
        this.amount = a;
        this.sm = sm;
    }

    @Override
    public void run() {
        sm.addProduct(amount);
    }

}

消费者

public class Consumer implements Runnable {
    private int amount;
    private StoreManager sm;

    public Consumer(int a, StoreManager sm) {
        this.amount = a;
        this.sm = sm;
    }

    @Override
    public void run() {
        sm.takeProduct(amount);
    }

}

测试

public class Test {
    public static void main(String[] args) {
        StoreManager sm = new StoreManager(0);
        for (int i = 0; i < 4; i++) {
            int a = (int) (Math.random() * 20) + 1;
            Thread t = new Thread(new Consumer(a, sm));
            t.start();
        }

        for (int i = 0; i < 5; i++) {
            int a = (int) (Math.random() * 20) + 1;
            Thread t = new Thread(new Producer(a, sm));
            t.start();
        }
    }
}

结果

仓库数量不够,不能取...
仓库数量不够,不能取...
仓库数量不够,不能取...
仓库数量不够,不能取...
生产了:20个,当前容量有:20个
生产了:2个,当前容量有:22个
消费了:7个,当前容量有:15个
生产了:12个,当前容量有:27个
消费了:6个,当前容量有:21个
消费了:12个,当前容量有:9个
消费了:1个,当前容量有:8个
生产了:11个,当前容量有:19个
生产了:11个,当前容量有:30个

results matching ""

    No results matching ""