一:单生产者单消费者:
分析:
- 两个线程:生产线程,消费线程
- 两个任务:生产任务,消费任务
- 一份数据
public class Demo03 {
public static void main(String[] args) {
//1.准备数据
Product product = new Product();
//2.创建生产消费任务
Producer producer = new Producer(product);
Consumer consumer = new Consumer(product);
//3.创建生产消费线程
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(consumer);
//4.开启线程
thread1.start();
thread2.start();
}
}
// 数据类
class Product {
String name;
double price;
int count;
// 标识
boolean flag ;// 默认是false
// 准备生产
public synchronized void setProduct(String name, double price) {
if (flag == true) {
try {
wait();
} catch (Exception e) {
// TODO: handle exception
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 (Exception e) {
// TODO: handle exception
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() {
int i = 0;
while (true) {
product.setProduct("肯德基", 100);
}
}
}
// 消费任务
class Consumer implements Runnable {
Product product;
public Consumer(Product product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}
二:多生产者多消费者:
分析
- 两个线程:生产线程,消费线程
- 两个任务:生产任务,消费任务
- 一份数据
错误描述:当有两个生产线程,两个消费线程同时存在的时候,有可能出现生产一次,消费多次或者生产多次消费一次的情况.
原因:当线程被重新唤醒之后,没有判断标记,直接执行了下面的代码
解决办法:将标记处的if改成while
问题描述:继续运行程序,会出现死锁的情况(4个线程同时处于等待状态)
原因:唤醒的是本方的线程,最后导致所有的线程都处于等待状态.
解决办法:将notify改成notifyAll.保证将对方的线程唤醒
死锁:出现的情况有两种
1.所有的线程处于等待状态
2.锁之间进行嵌套调用
public class Demo04 {
public static void main(String[] args) {
//1.准备数据
Product1 product = new Product1();
//2.创建生产消费任务
Producer1 producer = new Producer1(product);
Consumer1 consumer = new Consumer1(product);
//3.创建生产消费线程
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(consumer);
Thread thread3 = new Thread(producer);
Thread thread4 = new Thread(consumer);
//4.开启线程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
// 数据类
class Product1 {
String name;
double price;
int count;
// 标识
boolean flag ;// 默认是false
// 准备生产
public synchronized void setProduct(String name, double price) {
while (flag == true) {
try {
wait();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.name = name;
this.price = price;
System.out.println(Thread.currentThread().getName() + "生产了:" + name + " 产品的数量:" + count + " 价格是:" + price);
count++;
flag = !flag;
notifyAll();
}
// 准备消费
public synchronized void consume() {
while (flag == false) {
try {
wait();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "消费了:" + name + " 产品的数量:" + count + " 价格是:" + price);
flag = !flag;
notifyAll();
}
}
// 生产任务
class Producer1 implements Runnable {
Product1 product;
public Producer1(Product1 product) {
super();
this.product = product;
}
public void run() {
int i = 0;
while (true) {
product.setProduct("肯德基", 100);
}
}
}
// 消费任务
class Consumer1 implements Runnable {
Product1 product;
public Consumer1(Product1 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}
研究:研究Lock
比较synchronized和Lock
1.synchronized:从jdk1.0就开始使用的同步方法-称为隐式同步
synchronized(锁对象){//获取锁 我们将锁还可以称为锁旗舰或者监听器
同步的代码
}//释放锁
2.Lock:从jdk1.5开始使用的同步方法-称为显示同步
原理:Lock本身是接口,要通过他的子类创建对象干活儿
使用过程:
首先调用lock()方法获取锁
进行同步的代码块儿
使用unlock()方法释放锁
使用的场景:
当进行多生产者多消费者的功能时,使用Lock,其他的都使用synchronized
使用效率上:Lock高于synchronized
public class Demo05 {
public static void main(String[] args) {
// 1.准备数据
Product2 product = new Product2();
// 2.创建生产消费任务
Producer2 producer = new Producer2(product);
Consumer2 consumer = new Consumer2(product);
// 3.创建生产消费线程
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(consumer);
Thread thread3 = new Thread(producer);
Thread thread4 = new Thread(consumer);
// 4.开启线程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
// 数据类
class Product2 {
String name;
double price;
int count;
// 标识
boolean flag;// 默认是false
// 创建锁对象
Lock lock = new ReentrantLock();
//获取为生产任务提供唤醒等待的Condition对象
Condition conditionPro = lock.newCondition();
//获取为消费任务提供唤醒等待的Condition对象
Condition conditionCon = lock.newCondition();
// 准备生产
public void setProduct(String name, double price) {
try {
lock.lock();// 获取锁
while (flag == true) {
try {
conditionPro.await();//让生产线程等待
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.name = name;
this.price = price;
System.out
.println(Thread.currentThread().getName() + "生产了:" + name + " 产品的数量:" + count + " 价格是:" + price);
count++;
flag = !flag;
//肯定唤醒的是消费线程
conditionCon.signal();
} finally {//放的是必须执行的代码,功能:用于资源的释放
lock.unlock();// 释放
}
}
// 准备消费
public void consume() {
try {
lock.lock();
while (flag == false) {
try {
conditionCon.await();//让消费进程等待
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "消费了:" + name + " 产品的数量:" + count + " 价格是:" + price);
flag = !flag;
//肯定唤醒的是生产线程
conditionPro.signal();
} finally {
// TODO: handle finally clause
lock.unlock();
}
}
}
// 生产任务
class Producer2 implements Runnable {
Product2 product;
public Producer2(Product2 product) {
super();
this.product = product;
}
public void run() {
int i = 0;
while (true) {
product.setProduct("肯德基", 100);
}
}
}
// 消费任务
class Consumer2 implements Runnable {
Product2 product;
public Consumer2(Product2 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}
线程的停止:即如何停止它的任务
- 通过一个标识结束线程
- 调用stop方法——有固有的安全性问题,系统不推荐使用。
- 调用interrupt()方法。
//第一种方式:
/*public class Demo06 {
public static void main(String[] args) {
Test test = new Test();
Thread thread = new Thread(test);
thread.start();
try {
thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
int i = 0;
while(true) {
if(++i==10) {
test.flag=false;//当主线程执行到某个阶段时,让flag变成false,子线程的任务就会结束,子线程就结束了。
break; //目的是让主线程结束
}
}
}
}
class Test implements Runnable {
boolean flag = true;
public void run() {
while(flag) {
System.out.println(Thread.currentThread().getName()+"该下课了");
}
}
}*/
//第三种方式
public class Demo06 {
public static void main(String[] args) {
Test test = new Test();
Thread thread = new Thread(test);
thread.start();
try {
thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
int i = 0;
while(true) {
if(++i==10) {
//当主线程执行到某个阶段是,调用子线程的Interrupt方法,触发子线程的异常(InterruptedException),让子线程的任务结束,子线程结束
thread.interrupt();
break; //目的是让主线程结束
}
}
}
}
class Test implements Runnable {
boolean flag = true;
public synchronized void run() {
while(flag) {
try {
wait();
} catch (InterruptedException e) {
flag=false;
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"该下课了");
}
}
}