你的代码没有问题,我重新组织了一下,以便更好地观察结果。import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/**
 * 多线程生产者-消费者示例
 */
public class Basket {    public static final int BASKET_CAPACITY = 5;    private List<String> list = new ArrayList<>();    private Lock lock = new ReentrantLock();    private Condition setter = lock.newCondition(); //篮子为满的条件    private Condition getter = lock.newCondition(); //篮子为空的条件    // 放入苹果
    public void addApple() throws InterruptedException {
        try {
            lock.lock();
            while (list.size() >= BASKET_CAPACITY) {
                outputThreadMessage("篮子已满,等待取出", false);
                setter.await();
            }
            list.add("红富士");
            outputThreadMessage("放入苹果: 篮子里还有" + list.size(), false);            getter.signalAll();
        } finally {
            lock.unlock();
        }
    }    // 取出苹果
    public void removeApple() throws InterruptedException {
        try {
            lock.lock();
            while (list.size() <= 0) {
                outputThreadMessage("篮子已空,等待放入", true);
                getter.await();
            }
            list.remove(0);
            outputThreadMessage("取出苹果: 篮子里还有" + list.size(), true);            setter.signalAll();
        } finally {
            lock.unlock();
        }
    }    public static void main(String[] args) {
        final Basket baskert = new Basket();        // 通过调整 AddAppleTask 和 RemoveAppleTask 的线程数,可以
        // 观察篮子满或空的情况
        
        new Thread(new AddAppleTask(baskert)).start();
        new Thread(new AddAppleTask(baskert)).start();        new Thread(new RemoveAppleTask(baskert)).start();
        new Thread(new RemoveAppleTask(baskert)).start();
    }    /**
     * 放入苹果线程
     */
    private static class AddAppleTask implements Runnable {        private final Basket basket;        public AddAppleTask(Basket basket) {
            this.basket = basket;
        }        public void run() {
            try {
                while (waitRandomTime()) {
                    basket.addApple();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }    }    /**
     * 取出苹果线程
     */
    private static class RemoveAppleTask implements Runnable {        private final Basket basket;        public RemoveAppleTask(Basket basket) {
            this.basket = basket;
        }        public void run() {
            try {
                while (waitRandomTime()) {
                    basket.removeApple();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }        }    }    /////////////////////////////////////////////////////////    public static final Random RANDOM = new Random();    private static void outputThreadMessage(String message, boolean err) {
        if (err) {
            System.err.printf("[%10s] %s\n", Thread.currentThread().getName(), message);
        } else {
            System.out.printf("[%10s] %s\n", Thread.currentThread().getName(), message);
        }
    }    private static boolean waitRandomTime() {
        try {
            Thread.sleep(RANDOM.nextInt(1000) + 500);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }
}

解决方案 »

  1.   

    之前那个有问题,因为控制台的输出并不是严格按照先后顺序来的,所以不能依赖控制台输出来观察多线程的运行,必须先按照先后顺序把消息记下来,然后再一把输出。import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Random;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;/**
     * 多线程生产者-消费者示例
     */
    public class Basket {    public static final int BASKET_CAPACITY = 5;    private List<String> list = new ArrayList<>();    private Lock lock = new ReentrantLock();    private Condition setter = lock.newCondition(); //篮子为满的条件    private Condition getter = lock.newCondition(); //篮子为空的条件    // 放入苹果
        public void addApple() throws InterruptedException {
            try {
                lock.lock();
                while (list.size() >= BASKET_CAPACITY) {
                    addMessage("+++ 篮子已满,等待取出");
                    setter.await();
                }
                list.add("红富士");
                addMessage("+++ 放入苹果: 篮子里还有" + list.size());            getter.signalAll();
            } finally {
                lock.unlock();
            }
        }    // 取出苹果
        public void removeApple() throws InterruptedException {
            try {
                lock.lock();
                while (list.size() <= 0) {
                    addMessage("--- 篮子已空,等待放入");
                    getter.await();
                }
                list.remove(0);
                addMessage("--- 取出苹果: 篮子里还有" + list.size());            setter.signalAll();
            } finally {
                lock.unlock();
            }
        }    /////////////////////////////////////////////////////////    public static void main(String[] args) throws Exception {
            final Basket baskert = new Basket();        // 通过调整 AddAppleTask 和 RemoveAppleTask 的线程数,可以
            // 观察篮子满或空的情况        startTask(new AddAppleTask(baskert));
            startTask(new AddAppleTask(baskert));
            startTask(new AddAppleTask(baskert));        startTask(new RemoveAppleTask(baskert));
            startTask(new RemoveAppleTask(baskert));        System.out.println("线程运行中,请等待 10 秒...");        Thread.sleep(10000);    // 让线程运行 10 秒钟
            stop = true;
            Thread.sleep(2000);     // 等待所有线程停止        outputMessagesWithOrder();       // 按照次序打印消息
        }    private static void startTask(Runnable runnable) {
            Thread thread = new Thread(runnable);
            thread.setDaemon(true);
            thread.start();
        }    /////////////////////////////////////////////////////////    /**
         * 放入苹果线程
         */
        private static class AddAppleTask implements Runnable {        private final Basket basket;        public AddAppleTask(Basket basket) {
                this.basket = basket;
            }        public void run() {
                try {
                    while (waitRandomTime()) {
                        basket.addApple();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }    }    /**
         * 取出苹果线程
         */
        private static class RemoveAppleTask implements Runnable {        private final Basket basket;        public RemoveAppleTask(Basket basket) {
                this.basket = basket;
            }        public void run() {
                try {
                    while (waitRandomTime()) {
                        basket.removeApple();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }        }    }    /////////////////////////////////////////////////////////    public static final Random RANDOM = new Random();    private static boolean stop = false;    private static List<String> messages = new ArrayList<>();    private static final AtomicInteger serial = new AtomicInteger();    private static synchronized void addMessage(String message) {
            messages.add(String.format("%4d[%8s] %s",
                    serial.incrementAndGet(), Thread.currentThread().getName(), message));
        }    private static void outputMessagesWithOrder() {
            Collections.sort(messages);        for (String message : messages) {
                System.out.println(message);
            }
        }    private static boolean waitRandomTime() {
            try {
                Thread.sleep(RANDOM.nextInt(1000) + 500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return !stop;
        }
    }
      

  2.   

    谢谢
    不过你的输出结果和预期相同,是不是因为你waitRandomTime方法调用了sleep。为什么不用sleep执行顺序就不对,巧合吗
      

  3.   


    数量 50 100,500  结果都一样
    你代码耗时太低了,应该是计算线程优先级的问题,我这里调到30就能出现你想要的结果,加上Thread.sleep(1000)调到20就能出现你要的结果。