Java线程协作的两种方式小结

Java线程协作是指多个线程之间的相互协作来完成一个任务。在Java中,线程协作有两种方式:wait和notify/notifyAll。

Java线程协作是指多个线程之间的相互协作来完成一个任务。在Java中,线程协作有两种方式:wait和notify/notifyAll。

1. wait和notify

当线程需要等待某个条件时,可以调用wait方法。调用wait方法会使线程进入等待状态,直到另一个线程调用notify或notifyAll方法来唤醒它。

示例1:wait和notify的简单使用

下面的代码演示了wait和notify的简单使用方式:

public class WaitNotifyDemo {
    public static void main(String[] args) throws InterruptedException{
        Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                synchronized(lock) {
                    try {
                        System.out.println("Thread 1 is waiting");
                        lock.wait();
                        System.out.println("Thread 1 is awake");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                synchronized(lock) {
                    System.out.println("Thread 2 is running");
                    lock.notify();
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

这个例子中,有两个线程t1t2,它们共享了一个锁对象lock。线程t1在同步代码块中调用了lock.wait()方法,会使它进入等待状态。线程t2在同步代码块中调用了lock.notify()方法,唤醒了处于等待状态中的线程t1。程序输出结果为:

Thread 1 is waiting
Thread 2 is running
Thread 1 is awake

可以看到,线程t1等待了一段时间后被唤醒,才继续向下执行。

示例2:wait和notify解决生产者消费者问题

下面的代码使用wait和notify解决了生产者消费者问题:

public class ProducerConsumerDemo {
    private static final int MAX_SIZE = 10;
    private List<Integer> list = new ArrayList<Integer>();

    public static void main(String[] args) {
        ProducerConsumerDemo demo = new ProducerConsumerDemo();
        demo.start();
    }

    public void start() {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    private class Producer implements Runnable {
        public void run() {
            while (true) {
                synchronized (list) {
                    while (list.size() >= MAX_SIZE) {
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    int val = (int) (Math.random() * 100);
                    list.add(val);
                    System.out.println(Thread.currentThread().getName() + ": produce " + val);
                    list.notifyAll();
                }
            }
        }
    }

    private class Consumer implements Runnable {
        public void run() {
            while (true) {
                synchronized (list) {
                    while (list.size() == 0) {
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    int val = list.remove(0);
                    System.out.println(Thread.currentThread().getName() + ": consume " + val);
                    list.notifyAll();
                }
            }
        }
    }

}

这个例子中,有一个ProducerConsumerDemo类,它有一个共享的list变量,用来存放生产者生产的数据。Producer类实现了生产者的功能,Consumer类实现了消费者的功能。在Producer类中,当list中的元素数量达到最大值MAX_SIZE时,会调用list.wait()方法让该线程进入等待状态,一直到Consumer类消耗掉list中的元素后,唤醒它。在Consumer类中,当list为空时,会调用list.wait()方法让该线程进入等待状态,一直到Producer类生产出新的元素后,唤醒它。程序输出结果为:

Thread-0: produce 81
Thread-1: consume 81
Thread-0: produce 87
Thread-1: consume 87
Thread-0: produce 25
Thread-1: consume 25
...

可以看到,生产者和消费者之间实现了协作,生产者在list中存放数据,消费者从list中取走生产者生产的数据,生产者消费者的数量达到了平衡。

2. park和unpark

JDK1.5新增了Lock对象和Condition接口,其中Condition的await()方法是park的封装,signal()方法是unpark的封装。

示例1:park和unpark的简单使用

下面的代码演示了park和unpark的简单使用方式:

public class ParkUnparkDemo {
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                lock.lock();
                try {
                    System.out.println("Thread 1 is waiting");
                    condition.await();
                    System.out.println("Thread 1 is awake");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                lock.lock();
                try {
                    System.out.println("Thread 2 is running");
                    condition.signal();
                } finally {
                    lock.unlock();
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

这个例子中,有两个线程t1t2,它们共享了一个Lock对象和一个Condition对象。线程t1在同步代码块中调用了condition.await()方法,会使它进入等待状态。线程t2在同步代码块中调用了condition.signal()方法,唤醒了处于等待状态中的线程t1。程序输出结果为:

Thread 1 is waiting
Thread 2 is running
Thread 1 is awake

可以看到,线程t1等待了一段时间后被唤醒,才继续向下执行。

示例2:park和unpark解决生产者消费者问题

下面的代码使用park和unpark解决了生产者消费者问题:

public class ProducerConsumerDemo1 {
    private static final int MAX_SIZE = 10;

    private Lock lock = new ReentrantLock();

    private Condition notFull = lock.newCondition();

    private Condition notEmpty = lock.newCondition();

    private LinkedList<Integer> list = new LinkedList<Integer>();

    public static void main(String[] args) {
        ProducerConsumerDemo1 demo = new ProducerConsumerDemo1();
        demo.start();
    }

    public void start() {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    private class Producer implements Runnable {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (list.size() >= MAX_SIZE) {
                        notFull.await();
                    }
                    int val = (int) (Math.random() * 100);
                    list.add(val);
                    System.out.println(Thread.currentThread().getName() + ": produce " + val);
                    notEmpty.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    private class Consumer implements Runnable {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (list.size() == 0) {
                        notEmpty.await();
                    }
                    int val = list.removeFirst();
                    System.out.println(Thread.currentThread().getName() + ": consume " + val);
                    notFull.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

这个例子中,有一个ProducerConsumerDemo1类,它有一个共享的list变量,用来存放生产者生产的数据。Producer类实现了生产者的功能,Consumer类实现了消费者的功能。在Producer类中,当list中的元素数量达到最大值MAX_SIZE时,会调用notFull.await()方法让该线程进入等待状态,一直到Consumer类消耗掉list中的元素后,唤醒它。在Consumer类中,当list为空时,会调用notEmpty.await()方法让该线程进入等待状态,一直到Producer类生产出新的元素后,唤醒它。程序输出结果为:

Thread-0: produce 19
Thread-1: consume 19
Thread-0: produce 87
Thread-1: consume 87
Thread-0: produce 74
Thread-1: consume 74
...

可以看到,生产者和消费者之间实现了协作,生产者在list中存放数据,消费者从list中取走生产者生产的数据,生产者消费者的数量达到了平衡。

以上就是Java线程协作的两种方式的完整攻略,希望能对你有所帮助。

本文标题为:Java线程协作的两种方式小结

基础教程推荐