1.案例:wait/notify/notifyAll
方法简述:
wait:释放线程拥有的当前锁对象,让线程进入WAITING状态
notify:唤醒当前锁对象等待池(WaitSet)中,某一个线程
notifyAll:唤醒当前锁对象等待池(WaitSet)中,所有线程
业务描述:
1.通过wait与notify(notifyAll)实现线程协同,实现经典的生产者消费者模式
2.编写生产者,向队列中生产数据,如果队列满,生产者进行等待,并唤醒消费者进行消费
3.编写消费者,从队列中消费数据,如果队列空,消费者进行等待,并唤醒生产者进行生产
4.在主类main方法中,创建两个生产者线程进行生产
5.在主类main方法中,创建一个消费者线程进行消费
生产者:
/**
* 生产者
*/
class Producer implements Runnable{
public void run() {
while(true){
synchronized (ProducerConsumerDemo.LOCK){
// 检查队列是否满,推荐用while而不是if
while(ProducerConsumerDemo.QUEUE.size() ==
ProducerConsumerDemo.CAPACITY){
// 如果队列满,则等待消费者消费
try {
System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
Thread.currentThread().getName() + "】正在等待消费者消费.");
ProducerConsumerDemo.LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果队列不满,则正常生产
ProducerConsumerDemo.QUEUE.add(1);
System.out.println("线程【" + Thread.currentThread().getName() +
"】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
// 唤醒消费者
ProducerConsumerDemo.LOCK.notifyAll();
}
}
}
}
消费者:
/**
* 消费者
*/
class Consumer implements Runnable{
public void run() {
while(true){
synchronized (ProducerConsumerDemo.LOCK){
// 检查队列是否空,推荐用while而不是if
while(ProducerConsumerDemo.QUEUE.isEmpty()){
// 如果队列空,则等待生产者生产
try {
System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
Thread.currentThread().getName() + "】正在等待生产者生产.");
ProducerConsumerDemo.LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果队列不空,则正常消费
ProducerConsumerDemo.QUEUE.remove(0);
System.out.println("线程【" + Thread.currentThread().getName() +
"】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
// 唤醒生产者
ProducerConsumerDemo.LOCK.notifyAll();
}
}
}
}
完整代码:
package com.anan.thread.threadmethod;
import java.util.ArrayList;
/**
* 生产者消费者模型:wait与notify(notifyAll)
*/
public class ProducerConsumerDemo {
// 定义公共资源:队列容量、队列
public final static Integer CAPACITY = 6;
public final static ArrayList<Integer> QUEUE = new ArrayList<Integer>(CAPACITY);
// 定义锁对象
public final static Object LOCK = new Object();
public static void main(String[] args) {
// 创建两个生产者线程
Runnable r1 = new Producer();
Thread producer0 = new Thread(r1,"producer-0");
producer0.start();
Thread producer1 = new Thread(r1,"producer-1");
producer1.start();
// 创建消费者线程
Runnable r2 = new Consumer();
Thread consumer1 = new Thread(r2,"consumer-0");
consumer1.start();
}
}
/**
* 生产者
*/
class Producer implements Runnable{
public void run() {
while(true){
synchronized (ProducerConsumerDemo.LOCK){
// 检查队列是否满,推荐用while而不是if
while(ProducerConsumerDemo.QUEUE.size() ==
ProducerConsumerDemo.CAPACITY){
// 如果队列满,则等待消费者消费
try {
System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
Thread.currentThread().getName() + "】正在等待消费者消费.");
ProducerConsumerDemo.LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果队列不满,则正常生产
ProducerConsumerDemo.QUEUE.add(1);
System.out.println("线程【" + Thread.currentThread().getName() +
"】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
// 唤醒消费者
ProducerConsumerDemo.LOCK.notifyAll();
}
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
public void run() {
while(true){
synchronized (ProducerConsumerDemo.LOCK){
// 检查队列是否空,推荐用while而不是if
while(ProducerConsumerDemo.QUEUE.isEmpty()){
// 如果队列空,则等待生产者生产
try {
System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
Thread.currentThread().getName() + "】正在等待生产者生产.");
ProducerConsumerDemo.LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果队列不空,则正常消费
ProducerConsumerDemo.QUEUE.remove(0);
System.out.println("线程【" + Thread.currentThread().getName() +
"】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
// 唤醒生产者
ProducerConsumerDemo.LOCK.notifyAll();
}
}
}
}
2.案例
2.1.方法:sleep
方法简述:
1.让线程进入TIMED_WAITING状态
2.如果线程占有锁对象资源,不会释放锁
package com.anan.thread.threadmethod;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 线程方法sleep:
* 1.让线程进入TIMED_WAITING状态
* 2.如果线程占有锁对象资源,不会释放锁
*/
public class ThreadMethodSleepDemo {
// 锁
public final static Object LOCK = new Object();
public static void main(String[] args) {
// 创建Runnable对象
Runnable r1 = new MyRunnable();
// 创建两个线程对象
Thread t1 = new Thread(r1,"thread-0");
Thread t2 = new Thread(r1,"thread-1");
// 启动线程
t1.start();
t2.start();
}
}
/**
* 实现Runnable接口,创建线程
*/
class MyRunnable implements Runnable{
public void run() {
System.out.println("【" + Thread.currentThread().getName() + "】准备休眠.");
// 加锁,演示sleep不释放锁
synchronized (ThreadMethodSleepDemo.LOCK){
System.out.println("【" + Thread.currentThread().getName() + "】获取到锁.休眠进行中.");
int time = 0;
try {
Random random = new Random();
time = random.nextInt(6);
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【" + Thread.currentThread().getName() + "】随机休眠:" +time+ "秒时间到.释放锁.");
}
System.out.println("【" + Thread.currentThread().getName() + "】结束休眠.");
}
}
2.2.方法:join
方法简述:
1.方法join表示在一个线程中,加入另外一个线程
2.被加入线程,会等待【加入线程】执行完成
package com.anan.thread.threadmethod;
import java.util.concurrent.TimeUnit;
/**
* 线程方法join:
* 1.如果有线程加入我们,我们就等待加入线程执行完成
*/
public class ThreadMethodJoinDemo {
public static void main(String[] args) throws InterruptedException{
// 创建线程对象
Runnable r1 = new MyRunnable1();
Thread t1 = new Thread(r1,"thread-0");
t1.start();
// join方法
t1.join();
System.out.println("主线程main方法执行中.");
}
}
/**
* 实现Runnable接口,创建线程
*/
class MyRunnable1 implements Runnable{
public void run() {
for(int i = 0; i < 3; i++){
System.out.println(Thread.currentThread().getName() +
"第:【" + i + "】次执行.");
// 休眠10毫秒
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行结束.");
}
}
2.3.方法:yield
方法简述:
1.线程主动让出CPU执行时间
2.孔融让梨,和谐社会大家好
3.需要注意:这只是一种美德,不能对它产生依赖
package com.anan.thread.threadmethod;
/**
* 线程方法yield:
* 1.线程主动让出CPU执行时间
* 2.孔融让梨,和谐社会大家好
*/
public class ThreadMethodYieldDemo {
public static void main(String[] args) {
// 创建两个线程
Runnable r1 = new MyRunnable2();
Thread t0 = new Thread(r1, "thread-0");
Thread t1 = new Thread(r1, "thread-1");
// 线程t0
t0.start();
// yield方法,线程t1
t1.start();
t1.yield();
}
}
/**
* 实现Runnable接口,创建线程
*/
class MyRunnable2 implements Runnable{
public void run() {
for(int i = 0; i < 3; i++){
System.out.println("【" + Thread.currentThread().getName() +
"】第:【" + i + "】次执行.");
}
System.out.println("【" + Thread.currentThread().getName() +
"】执行结束.");
}
}
关于作者
王硕,网名信平,十多年软件开发经验,业余架构师,精通Java/Python/Go等,喜欢研究技术,著有《PyQt 5 快速开发与实战》《Python 3.* 全栈开发》,多个业余开源项目托管在GitHub上,欢迎微博交流。