java多线程:线程的通信、唤醒等待机制、生产消费者模式、Lock

本文介绍了线程通信的基本概念及其实现方式,包括通过共享数据实现线程间同步、使用wait/notify机制确保线程有序执行、以及采用生产者消费者模式解决多线程间的协调问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程的通信:打印机打印–不断的输入输出

package com.qianfeng.test;
/*
 * 线程的通信:
 * 分析:
 * 需要两个线程--输入线程和输出线程
 * 需要两个任务--输入任务和输出任务
 * 需要一份数据
 * 
 * 实现:打印机打印--不断的输入不断的输出
 * 
 */
public class Demo2 {

	public static void main(String[] args) {
		
		//1.创建数据类对象
		Des des =new Des();
		//创建任务类对象并绑定数据
		Input input = new Input(des);
		Output output = new Output(des);
		//3.创建线程
		Thread inputThread = new Thread(input);
		Thread outputThread = new Thread(output);
		//4.开启线程
		inputThread.start();
		outputThread.start();
		
	}
}

//创建数据类
class Des{
	String name;
	String sex;
}

//创建输入任务
class Input implements Runnable{

	Des des;
	public Input(Des des){
		this.des=des;
	}
	
	public void run() {
		/*
		 * 分析:需要输入任务与输出任务共用一把锁,保证两个任务之间是同步的。
		 * 给两个任务加一把锁,锁可以是des或Object.class
		 * 
		 * 不建议使用Object.class,因为Object.class应用范围太大,其它地方可能也会用到。
		 * 使用des最合适,因为它只被两个线程共享。
		 * 
		 * 注意:只给一个任务加锁无法实现两个线程的同步。
		 */
		int i = 0;
		while(true){
			synchronized (des) {
				if (i==1) {
					des.name = "凤姐";
					des.sex = "男" ;
				}else {
					des.name = "芙蓉姐姐";
					des.sex = "女" ;
				}
				i=(i+1)%2;
			}
		}
	}
}

//创建输出任务
class Output implements Runnable{

	Des des;
	public Output(Des des){
		this.des=des;
	}
	
	public void run() {
		while(true){
			synchronized (des) {
				System.out.println("姓名:"+des.name+"  性别"+des.sex);
			}
		}
	}
}

唤醒等待机制,wait()/notify()/notifyAll()

package com.qianfeng.test;

/*
 * 线程的通信:
 * 分析:
 * 需要两个线程--输入线程和输出线程
 * 需要两个任务--输入任务和输出任务
 * 需要一份数据
 * 
 * 实现:打印机打印--一次输入一次输出
 * 
 * 使用唤醒等待机制实现:wait()/notify()/notifyAll()等
 * wait():让当前的线程进入等待的状态,他会被放入一个池子(线程池),失去了抢cpu的能力,等待唤醒。(锁--相当于给当前线程做了一个标记)
 * notify():让当前的线程从等待线程唤醒,相当于从池子中取出线程。(唤醒的是同一把锁下的任意一个线程)
 * notifyAll():唤醒的是同一把锁下的所有线程。
 */
public class Demo3 {

	public static void main(String[] args) {

		// 1.创建数据类对象
		Des1 des = new Des1();
		// 创建任务类对象并绑定数据
		Input1 input = new Input1(des);
		Output1 output = new Output1(des);
		// 3.创建线程
		Thread inputThread = new Thread(input);
		Thread outputThread = new Thread(output);
		// 4.开启线程
		inputThread.start();
		outputThread.start();

	}
}

// 创建数据类
// 封装类的原则:是你的活你做,不是你的活不要做。
class Des1 {
	String name;
	String sex;
	boolean flag = false;// 创建一个标识,控制唤醒与等待的切换。

	// 获取数据--处理输入
	public synchronized void setData(String name, String sex) {
		if (flag == true) {
			try {// 让输入线程等待,当flag值为true的时候
					// 在执行代码的时候,这里对应的是哪个线程,锁对象操作的就是哪个线程。
				wait();// 只要一执行wait,线程会立刻停在这里,等待下次唤醒。
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		this.name = name;
		this.sex = sex;

		flag = !flag;
		 唤醒输出线程。
		// 当执行唤醒的时候,在线程池中没有找到被当前的锁标记的线程,我们称为空唤醒,空唤醒对程序没有影响,程序允许空唤醒。
		notify();

	}

	// 将数据打印到控制台--处理输出
	public synchronized void getData() {
		if (flag == false) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("姓名:" + name + "  性别" + sex);
		flag = !flag;
		notify();
	}

}

// 创建输入任务
class Input1 implements Runnable {

	Des1 des;
	public Input1(Des1 des) {
		this.des = des;
	}

	public void run() {
		
		int i = 0;
		while (true) {
			if (i == 1) {
				des.setData("凤姐", "男");
			} else {
				des.setData("芙蓉姐姐", "女");
			}
			i = (i + 1) % 2;
		}
	}
}

// 创建输出任务
class Output1 implements Runnable {

	Des1 des;
	public Output1(Des1 des) {
		this.des = des;
	}

	public void run() {
		while(true){
			des.getData();
		}

	}
}

多线程设计模式:单生产者单消费者

package com.qianfeng.test;
/*
 * 多线程的设计模式:生产者消费者
 * 两类:
 * 1.单生产者单消费者
 * 2.多生产者多消费者
 * 
 * 先研究单生产者单消费者
 * 分析:
 * 生产线程,消费线程
 * 生产任务,消费任务
 * 产品
 */
public class Demo4 {
	public static void main(String[] args) {
		//1.创建产品
		Product product = new Product();
		//2.创建生产任务,消费任务
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		
		//3.创建生产线程,消费线程
		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);
		
		//4.开启线程
		t1.start();
		t2.start();
	}
}

//创建产品类
class Product{
	String name;
	double price;
	int count;
	
	boolean flag = false;//用来在唤醒与等待之间进行切换
	
	//为生产准备数据
	public synchronized void setProduce(String name,double price){
		if (flag == true) {
			try {
				wait();//让生产线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		this.name = name;
		this.price = price;
		
		System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
		count++;
		
		flag = ! flag;
		notify();//唤醒消费线程
	}
	//为消费准备数据
	public  synchronized void consume() {
		if (flag == false) {
			try {
				wait();//让消费线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
		
		flag = ! flag;
		notify();//唤醒生产线程
	}
}

//创建生产任务
class Producer implements Runnable{
	Product product;
	public Producer(Product product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
	}
}
//创建消费任务
class Consumer implements Runnable{
	Product product;
	public Consumer(Product product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.consume();
		}
	}
}

多线程设计模式:多生产者多消费者

package com.qianfeng.test;
/*
 * 多线程的设计模式:生产者消费者
 * 两类:
 * 1.单生产者单消费者
 * 2.多生产者多消费者
 * 
 * 研究多生产者多消费者
 * 分析:
 * 生产线程,消费线程有多个
 * 生产任务,消费任务各有一个
 * 产品一个
 */
public class Demo5 {
	public static void main(String[] args) {
		//1.创建产品
		Product1 product = new Product1();
		//2.创建生产任务,消费任务
		Producer1 producer = new Producer1(product);
		Consumer1 consumer = new Consumer1(product);
		
		//3.创建生产线程,消费线程
		Thread t0 = new Thread(producer);
		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);
		Thread t3 = new Thread(consumer);
		
		//4.开启线程
		t0.start();
		t1.start();
		t2.start();
		t3.start();
		
	}
}

//创建产品类
class Product1{
	String name;
	double price;
	int count;
	
	boolean flag = false;//用来在唤醒与等待之间进行切换
	
	//为生产准备数据
	public synchronized void setProduce(String name,double price){
		while (flag == true) {
			try {
				wait();//让生产线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		this.name = name;
		this.price = price;
		
		System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
		count++;
		
		flag = ! flag;
		//notify();//唤醒消费线程
		notifyAll();
	}
	//为消费准备数据
	public  synchronized void consume() {
		while (flag == false) {
			try {
				wait();//让消费线程等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
		
		flag = ! flag;
		//notify();//唤醒生产线程
		notifyAll();
	}
}

//创建生产任务
class Producer1 implements Runnable{
	Product1 product;
	public Producer1(Product1 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
	}
}
//创建消费任务
class Consumer1 implements Runnable{
	Product1 product;
	public Consumer1(Product1 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.consume();
		}
	}
}

Lock,Condition。Lock与synchronized的比较

package com.qianfeng.test;

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

/*
 * Lock:
 * 比较synchronized和Lock
 * 1.synchronized:从jdk1.0开始使用----隐式同步
 * 	synchronized(锁对象){//获取锁   我们将这里的锁称为锁旗舰或者监听器
 * 		同步的代码
 * }//释放锁
 * 2.Lock:从jdk1.5开始使用----显示同步
 * 原理:Lock是接口,我们要通过他的子类工作
 * 具体的工作流程:
 * 	首先调用lock的lock()方法,获取锁
 *      进行同步操作的代码
 *  调用lock的unlock()方法,释放锁
 *  
 *  使用场景总结:
 *  1.当进行多生产者的消费者的时候,使用lock,其他的使用synchronized
 *  
 *  使用效率上lock比synchronized高.
 */

public class Demo6 {
	public static void main(String[] args) {
		//1.创建产品
		Product2 product = new Product2();
		//2.创建生产任务,消费任务
		Producer2 producer = new Producer2(product);
		Consumer2 consumer = new Consumer2(product);
		
		//3.创建生产线程,消费线程
		Thread t0 = new Thread(producer);
		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);
		Thread t3 = new Thread(consumer);
		
		//4.开启线程
		t0.start();
		t1.start();
		t2.start();
		t3.start();
		
	}
}

//创建产品类
class Product2{
	String name;
	double price;
	int count;
	
	boolean flag = false;//用来在唤醒与等待之间进行切换
	
	//创建Lock的对象
	Lock lock = new ReentrantLock();
	
	//创建用于生产线程的Condition对象
	Condition proCon = lock.newCondition();
	//创建用于消费线程的Condition对象
	Condition conCon = lock.newCondition();
	
	//为生产准备数据
	public  void setProduce(String name,double price){
		try {
			lock.lock();//获取锁
			while (flag == true) {
				try {
					//wait();//让生产线程等待
					proCon.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			this.name = name;
			this.price = price;
			
			System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
			count++;
			
			flag = ! flag;
			//notify();//唤醒消费线程
			//notifyAll();
			conCon.signal();
		
		} finally {//必须执行的代码
			lock.unlock();//释放锁
		}
		
	}
	//为消费准备数据
	public   void consume() {
	    try {
			lock.lock();
			while (flag == false) {
				try {
					//wait();//让消费线程等待
					conCon.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
			
			flag = ! flag;
			//notify();//唤醒生产线程
			//notifyAll();
			proCon.signal();
		} finally {
			lock.unlock();
		}
		
	}
}

//创建生产任务
class Producer2 implements Runnable{
	Product2 product;
	public Producer2(Product2 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.setProduce("bingbing", 10);
		}
	}
}
//创建消费任务
class Consumer2 implements Runnable{
	Product2 product;
	public Consumer2(Product2 product) {
		super();
		this.product = product;
	}
	public void run() {
		while (true) {
			product.consume();
		}
	}
}

守护线程,setDaemon。

package com.qianfeng.test;
/*
 * 守护线程:相当于后台线程,依赖于前台线程。正常情况下,当前台线程结束的时候,不管后台线程有没有结束,都会立即结束。
 * 典型的守护线程:垃圾回收线程。
 * 
 */
public class Demo7 {

	public static void main(String[] args) {
		
		Test test = new Test();
		Thread thread = new Thread(test);
		/*
		 * 当程序调用setDaemon的时候,并且将参数设置为true,他就变成了守护线程。
		 * 注意:这个方法一定要在start方法之前调用。
		 */
		thread.setDaemon(true);
		thread.start();
		
		int i = 0;
		while(true){
			if (i++ == 10 ) {
				System.out.println(Thread.currentThread().getName()+" i"+i);
				break;//主线程结束
			}
		}
	}
}

class Test implements Runnable{

	public void run() {
		while(true){
			System.out.println("守护线程");
		}
		
	}
}

join方法

package com.qianfeng.test;
/*
 * join()方法:
 * 原理:程序一旦调用了join方法,他的优先级会高于主线程。意思是说,主线程会等当前线程执行完后再去执行。
 * 注意:这个线程的优先级只比main高,对其它的线程没有影响。
 * 
 */
public class Demo8 {

	public static void main(String[] args) {
		
		Dog dog = new Dog();
		Thread thread0 = new Thread(dog);
		Thread thread1 = new Thread(dog);
		thread0.start();
		thread1.start();
		
		/*
		 * 当线程开始工作后,让thread0调用join()方法,它的优先级会高于main线程。
		 * 注意:join()方法必须在线程开始工作后执行
		 */
		try {
			thread0.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+" i"+i);
		}
		
	}
}

class Dog implements Runnable{

	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+" i"+i);
		}
		
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值