IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> Java线程安全 |死锁问题与解决方案 -> 正文阅读

[PHP知识库]Java线程安全 |死锁问题与解决方案

买票问题产生线程安全问题

问题产生背景

  • 场景1: 一个窗口卖100张票,单线程不会产生共享数据也不会导致线程安全问题
  • 场景2: 1号窗口卖(0-33) 2号窗口卖(34-66) 3号窗口卖(67-100)票 不存在共享数据也不会导致线程安全问题
  • 场景3: 1-3号窗口同时卖1-100号票 存在共享数据会导致线程安全问题

代码模拟

  • RunnableImpl.java
package com.su27.ThreadSafe;

public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private int ticket = 100;
    // 设置线程任务*卖票
    @Override
    public void run(){
        while(true){
            // 先判断票是否存在
            if(ticket>0){
                // 提高线程安全问题出现概率
                try {
                    Thread.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                // 票存在 卖票ticket--
                System.out.println(Thread.currentThread().getName()+"--->正在卖第"+(ticket--)+"张票");
            }
        }
    }
}

  • Demo.java
package com.su27.ThreadSafe;

// 模拟卖票案例
// 创建3个线程,同时开启,对共享票出售
public class Demo {
    public static void main(String[] args) {
        // 创建Runnale接口的实现类对象
        RunnableImpl run = new RunnableImpl();
        // 创建Thread类对象 构造方法中 传递Runnable接口的实现类对象
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        // 调用start调用多线程
        t0.start();
        t1.start();
        t2.start();
    }
}

Thread-2--->正在卖第3张票
Thread-2--->正在卖第1张票
Thread-1--->正在卖第-1张票 // 线程安全问题 出现超卖
Thread-0--->正在卖第0张票 // 线程安全问题 出现超卖

分析产生原因

  • 卖票产生重复不存在
  • 同时3个线程度同一共享票数

解决线程安全问题

同步代码块

  • 使用synchronized关键字传入锁对象并将 有线程安全问题的代码块 放入同步代码块
package com.su27.SolveThreadSafe;
/*
解决线程安全问题方案一:使用同步代码块
格式:
synchronized(锁对象){
    可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
1.通过代码块中的锁对象,可以使用任意对象
2. 但必须保证多个线程使用锁对象是同一个
3. 锁对象作用:
    把同步代码块锁住,只让一个线程在同步代码块中执行
 */
public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private int ticket = 100;

    // 创建一锁对象
    Object obj = new Object();

    // 设置线程任务*卖票
    @Override
    public void run(){
        while(true){
            // 同步代码块
            synchronized (obj){
                // 先判断票是否存在
                if(ticket>0){
                    // 提高线程安全问题出现概率
                    try {
                        Thread.sleep(10);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    // 票存在 卖票ticket--
                    System.out.println(Thread.currentThread().getName()+"--->正在卖第"+(ticket--)+"张票");
                }
            }
        }
    }
}

同步技术原理

  • 同步代码块线程,没有执行完毕不释放锁,同步外线程没有锁进不去同步代码块,保证始终只能有一个线程执行,频繁上/下锁,降低效率,但避免线程安全问题

同步方法

  • 定义synchronized修饰的方法将有线程安全问题的代码放入其中
package com.su27.SolveThreadSafe1;
/*
解决线程安全问题方案一:使用同步方法
使用步骤:
1. 把访问了共享数据代码抽取出来,放到方法中
2. 在方法上加synchronized修饰符
格式: 修饰符 synchronized 返回类型 方法名(参数列表){
    共享数据代码
}
注意:
1.通过代码块中的锁对象,可以使用任意对象
2. 但必须保证多个线程使用锁对象是同一个
3. 锁对象作用:
    把同步代码块锁住,只让一个线程在同步代码块中执行
 */
public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private int ticket = 100;

    // 创建一锁对象
    Object obj = new Object();

    // 设置线程任务*卖票
    @Override
    public void run(){
        while(true){
            // 同步代码块
            payTicket();
        }
    }

    /*定义同步方法*/
    public synchronized void payTicket() {
        // 先判断票是否存在
        if(ticket>0){
            // 提高线程安全问题出现概率
            try {
                Thread.sleep(10);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            // 票存在 卖票ticket--
            System.out.println(Thread.currentThread().getName()+"--->正在卖第"+(ticket--)+"张票");
        }
    }
}
  • 注意 同步方法的锁对象就是实现对象 new RunnableImpl()也就是this
  • 验证this例子
/*定义同步方法*/
    public /*synchronized*/ void payTicket() {
        synchronized(this){
            // 先判断票是否存在
            if(ticket>0){
                // 提高线程安全问题出现概率
                try {
                    Thread.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                // 票存在 卖票ticket--
                System.out.println(Thread.currentThread().getName()+"--->正在卖第"+(ticket--)+"张票");
            }
        }

    }

死锁问题

  • A B同时执行 A首先加1锁 B首先加2锁 A下一步要2锁 B要1锁 产生锁的嵌套
    就发生死锁情况,互相因为得不到对方手中的资源无法释放当前各种资源。
package com.su27.DeadLock;

public class Demo {
    public static void main(String[] args) {

        Object objA = new Object();
        Object objB = new Object();

        new Thread(()->{
            while (true){
                synchronized (objA){
                    synchronized (objB){
                        System.out.println("小康同学在走路");
                    }
                }
            }
        }).start();

        new Thread(()->{
            while (true){
                synchronized (objB){
                    synchronized (objA){
                        System.out.println("小微同学在走路");
                    }
                }
            }
        }).start();
    }
}

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 09:51:10  更:2021-09-18 09:52:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:41:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码