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();
}
}
这个例子中,有两个线程t1
和t2
,它们共享了一个锁对象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();
}
}
这个例子中,有两个线程t1
和t2
,它们共享了一个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线程协作的两种方式小结 - Python技术站