文章目录
- 🌺lock锁
- ⭐获得锁
- ⭐释放锁
- ✨注意
- 🏳️🌈代码实现
- 🎈细节
- 🌺死锁
- ⭐解决方法
- 🎄等待唤醒机制
- ⭐代码实现
- 🎈注意
- 🛸使用阻塞队列实现等待唤醒机制
- 🍔线程的六种状态
比如下面这一段代码
我们在上一篇文章中讲过,进程进入synchroized后,其他进程不能进入,每次只允许执行一个进程
那么我们要想自定义运行过程,比如手动打开或者手动关闭,那么就应该使用lock锁
🌺lock锁
⭐获得锁
void lock();
⭐释放锁
void unlock();
✨注意
lock是接口不能直接实例化(即不能创建对象)
,可以采用它的实现类ReentrantLock来实例化
构造方法
Lock lock=new ReentrantLock();
🏳️🌈代码实现
MyRunnable.java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyRunnable implements Runnable {static int ticket = 0;static Lock lock = new ReentrantLock();@Overridepublic void run() {while (true) {lock.lock();try {if (ticket == 100) {break;} else {Thread.sleep(10);ticket++;System.out.println(Thread.currentThread().getName() + "在卖第" + ticket + "张票!!!");}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}
}
ThreadDemo.java
public class ThreadDemo {public static void main(String[] args) {MyRunnable mr=new MyRunnable();Thread t1=new Thread(mr);Thread t2=new Thread(mr);Thread t3=new Thread(mr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}
🎈细节
我们发现,虽然已经到了100张票,但是
程序没有停止运行
,这是为什么呢
线程一break了,但是没有运行unlock,导致二,三线程不能向下执行,所以程序不会停止运行
改进方法
加上finally就行了,因为程序一定会执行finally中的代码
🌺死锁
比如 线程A 等待 线程B 释放锁,线程B 等待 线程A 释放锁,这样子二者就会卡死,这就是死锁
⭐解决方法
就是以后写代码的时候,尽量不要把2个锁嵌套起来
🎄等待唤醒机制
我们可以这样子来形容这个机制
比如顾客(消费者)和厨师(生产者)之间的关系
⭐代码实现
🤖Foodie.java
public class Foodie extends Thread{@Overridepublic void run() {/** 1. 循环* 2. 同步代码块* 3. 判断共享数据是否到了末尾(到了末尾)* 4. 判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)* */while(true){synchronized (Desk.lock){if(Desk.count == 0){break;}else{//先判断桌子上是否有面条if(Desk.foodFlag == 0){//如果没有,就等待try {Desk.lock.wait();//让当前线程跟锁进行绑定} catch (InterruptedException e) {e.printStackTrace();}}else{//把吃的总数-1Desk.count--;//如果有,就开吃System.out.println("吃货在吃面条,还能再吃" + Desk.count + "碗!!!");//吃完之后,唤醒厨师继续做Desk.lock.notifyAll();//修改桌子的状态Desk.foodFlag = 0;}}}}}
}
🤖Cook.java
public class Cook extends Thread{@Overridepublic void run() {/** 1. 循环* 2. 同步代码块* 3. 判断共享数据是否到了末尾(到了末尾)* 4. 判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)* */while (true){synchronized (Desk.lock){if(Desk.count == 0){break;}else{//判断桌子上是否有食物if(Desk.foodFlag == 1){//如果有,就等待try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else{//如果没有,就制作食物System.out.println("厨师做了一碗面条");//修改桌子上的食物状态Desk.foodFlag = 1;//叫醒等待的消费者开吃Desk.lock.notifyAll();}}}}}
}
🤖Desk.java
public class Desk {/** 作用:控制生产者和消费者的执行** *///是否有面条 0:没有面条 1:有面条public static int foodFlag = 0;//总个数public static int count = 10;//锁对象public static Object lock = new Object();}
🤖ThreadDemo.java
public class ThreadDemo {public static void main(String[] args) {/*** 需求:完成生产者和消费者(等待唤醒机制)的代码* 实现线程轮流交替执行的效果** *///创建线程的对象Cook c = new Cook();Foodie f = new Foodie();//给线程设置名字c.setName("厨师");f.setName("吃货");//开启线程c.start();f.start();}
}
🎈注意
1.继承Thread类的主要目的是为了能够重写Thread类中的run()方法
2.为了可以共用同一个资源,Desk类的对象中要加上static
3.锁对象是唯一的
🛸使用阻塞队列实现等待唤醒机制
创建阻塞队列的对象
ArrayBlockingQueue < String > queue = new ArrayBlockingQueue<>(1);
🤖Cook.java
import java.util.concurrent.ArrayBlockingQueue;public class Cook extends Thread{ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不断的把面条放到阻塞队列当中try {queue.put("面条");System.out.println("厨师放了一碗面条");} catch (InterruptedException e) {e.printStackTrace();}}}
}
🤖Foodie.java
import java.util.concurrent.ArrayBlockingQueue;public class Foodie extends Thread{ArrayBlockingQueue<String> queue;public Foodie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不断从阻塞队列中获取面条try {String food = queue.take();System.out.println(food);} catch (InterruptedException e) {e.printStackTrace();}}}
}
🤖ThreadDemo.java
import java.util.concurrent.ArrayBlockingQueue;public class ThreadDemo {public static void main(String[] args) {/*** 需求:利用阻塞队列完成生产者和消费者(等待唤醒机制)的代码* 细节:* 生产者和消费者必须使用同一个阻塞队列** *///1.创建阻塞队列的对象ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);//2.创建线程的对象,并把阻塞队列传递过去Cook c = new Cook(queue);Foodie f = new Foodie(queue);//3.开启线程c.start();f.start();}
}
🍔线程的六种状态
如果大家有什么不明白的地方,请在评论区进行讨论