根据上一个博客,我们还剩下一下内容:
多线程的死锁、线程的同步以及线程的通信问题
线程的死锁问题:
死锁的理解:不同的线程分别占用对方的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
说明:出现死锁的时候,不会出现异常,不会出现提示,只是所有线程都会处于阻塞状态,无法继续执行
我们使用同步的时候,要避免死锁的出现。
/**
* @Auther:Yuhai
* @Date:2022/4/15-04-15-21:41
* @Description:IntelliJ IDEA
* @version:1.0
*/
/**
* 死锁代码的演示
* 造成死锁的原因:
* 当一个线程拥有A对象锁,并等待B对象锁的时候,另一个线程拥有B对象锁,并等待A对象锁,这就造成了死锁。
* 定义鞋的方向
* 此时代码的演示中会发现小明和小红再抢一只鞋子,这就会出现死锁的状态,他们在抢同一个资源
*/
//定义鞋的方向
class Shoes{
public static String left = "leftShoes";
public static String right = "rightShoes";
}
//当两个线程都在强同一个资源时,就会出现线程的安全性问题,当然,如果一个两个线程都在同时等待彼此资源的释放,那么,就会出现死锁的状态,这是因为胡互不谦让的结果,
// 所以在实际开发当中,应避免这中操作的出现
public class DeadLock {
public static void main(String[] args) {
Runnable xaioming = new Runnable() {
@Override
public void run() {
synchronized (Shoes.left){
System.out.println("小明拿到了左脚的鞋子");
synchronized (Shoes.right){
System.out.println("小明拿到了右脚鞋子,他可以穿鞋子走人了****");
}
}
}
};
Runnable xiaohong = new Runnable() {
@Override
public void run() {
synchronized (Shoes.right){
System.out.println("小红拿到了右脚鞋子");
synchronized (Shoes.left){
System.out.println("小红拿到了左脚鞋子,也可以穿鞋子走人*******");
}
}
}
};
Thread thread1 =new Thread(xaioming,"小明");
Thread thread2 =new Thread(xiaohong,"小红");
thread1.start();
thread2.start();
}
}
如何解决线程的死锁问题: 尽量避免嵌套同步,减少同步资源的定义,专门的算法、原则
在我们的实际开发过程中,应当避免死锁的出现。
线程的同步问题:共享数据会出现线程的安全性问题。
我么可以使用同步代码块和同步方法来解决线程安全性问题
同步代码块:简称锁
synchronize(同步监视器)在实现Runnable接口的时候天生共享锁
在thread中需要使用static对象和this关键字或者当前类的对象(对象.class)来充当锁
同步方法:使用同步方法,对其方法进行synchronize关键字的修饰
将同步代码块提取出来成为有一个方法,只需要将同步方法用synchronize修饰
对于runnable接口实现多线程,只需要将同步的方法用static和synchronize修饰,因为独享不唯一
接下来列出一个简单的例子:
四个窗口共卖100张票,保证每个窗口都可以卖票,不会抢占资源(这是使用同步方法来解决线程的安全性问题)
public class TicketImplements implements Runnable{
int tick = 100;
Object object = new Object();
@Override
public void run() {
while (tick>0){
//线程进来以后,遇到同步方法就只能进去一个线程
Method();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void Method(){
//判断一个票数的情况,如果票数大于零的情况下,就继续买票,进行减少的操作,
if (tick>0){
System.out.println(Thread.currentThread().getName()+"正在售卖第"+tick+"几张票");
tick--;
}
}
public static void main(String[] args) {
TicketImplements t = new TicketImplements();
new Thread(t, "窗口一").start();
new Thread(t, "窗口二").start();
new Thread(t, "窗口三").start();
new Thread(t, "窗口四").start();
}
}
线程的通信问题:我们可以在这里学到以下的几个方法
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
notify(): 一旦执行此方法,就会唤醒wait()的一个线程,如果有多个wait,就会唤醒优先级最高的哪一个
notifyAll():一旦执行此方法,就会唤醒所有的wait的程序
说明:
wait(),notify(),notifyAll()方法必须使用在同步方法或同步代码块中
wait(),notify(),notifyAll()方法的调用必须是同步方法和同步代码块中的同步监视器。
否则,会出现IllegalMonitsatreException 异常
wait(),notify(),notifyAll()方法定义在java.lang.object类中
接下来举一个简单的例子:利用队列来演示的生产者与消费者的例子
/**
* @Auther:Yuhai
* @Date:2022/4/18-04-18-10:00
* @Description:IntelliJ IDEA
* @version:1.0
*/
/*
共享数据源,商品的数据源。
*/
public class Goods {
private String brand;
private String name;
public Goods(String brand, String name) {
this.brand = brand;
this.name = name;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* @Auther:Yuhai
* @Date:2022/4/18-04-18-10:02
* @Description:IntelliJ IDEA
* @version:1.0
*/
/*
生产者生产产品。
*/
public class ProducerQueue implements Runnable {
//阻塞队列
private BlockingQueue<Goods> blockingQueue;
public ProducerQueue(BlockingQueue<Goods> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Goods goods = null;
if (i%2 == 0){
goods = new Goods("娃哈哈","矿泉水");
}else{
goods = new Goods("旺仔","小馒头");
}
System.out.println("生产者生产了产品-------"+goods.getBrand()+"-----"+goods.getName());
//将商品放在队列中去
try {
blockingQueue.put(goods);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
以上是生产者
消费者
/**
* @Auther:Yuhai
* @Date:2022/4/18-04-18-10:10
* @Description:IntelliJ IDEA
* @version:1.0
*/
//消费者队列
public class ConsumerQueue implements Runnable {
private BlockingQueue<Goods> blockingQueue;
public ConsumerQueue(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
Goods goods = null;
//从队列中取数据
try {
goods = blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费了产品-------"+goods.getBrand()+"-------"+goods.getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}