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 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java面向对象之线程的生命周期、线程的同步、互斥锁、线程的死锁及释放锁 -> 正文阅读

[Java知识库]Java面向对象之线程的生命周期、线程的同步、互斥锁、线程的死锁及释放锁

1、线程的生命周期

1.1、JDK 中用 Thread.State 枚举表示了线程的几种状态

在这里插入图片描述

1.2、线程状态转换图

在这里插入图片描述

1.3、查看线程状态

package state_;

public class ThreadState_ {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        System.out.println(t.getName() + "状态: " + t.getState());  // Thread-0状态: NEW
        t.start();
        while (Thread.State.TERMINATED != t.getState()) {
            System.out.println(t.getName() + "状态: " + t.getState());
            /*
            Thread-0状态: RUNNABLE
            hi 0
            Thread-0状态: TIMED_WAITING
            hi 1
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 2
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 3
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 4
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 5
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 6
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 7
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 8
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
            hi 9
            Thread-0状态: TIMED_WAITING
            Thread-0状态: TIMED_WAITING
             */
            Thread.sleep(500);
        }
        System.out.println(t.getName() + "状态: " + t.getState());  // Thread-0状态: TERMINATED
    }
}

class T extends Thread {
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 10; i++) {
                System.out.println("hi " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}

2、线程的同步

2.1、问题引出

在这里插入图片描述

2.2、Synchronized

2.2.1、线程同步机制

在这里插入图片描述

2.2.2、同步具体方法 - Synchronized

在这里插入图片描述

2.2.3、分析同步原理

在这里插入图片描述

3、互斥锁

3.1、基本介绍

在这里插入图片描述

3.2、使用互斥锁来解决售票问题

package syn;

/**
 * 使用多线程, 模拟三个窗口同时售票 100 张
 */
public class SellTicket {
    public static void main(String[] args) {
        // 测试
        /*
        System.out.println("=== 继承Thread方式来售票 ===");
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();
        // 这里我们会出现超卖
        sellTicket01.start();  // 启动售票线程
        sellTicket02.start();  // 启动售票线程
        sellTicket03.start();  // 启动售票线程


        System.out.println("=== 使用实现接口方式来售票 ===");
        SellTicket02 sellTicket021 = new SellTicket02();
        new Thread(sellTicket021).start();  // 第 1 个线程-窗口
        new Thread(sellTicket021).start();  // 第 2 个线程-窗口
        new Thread(sellTicket021).start();  // 第 3 个线程-窗口

        // 结论: 这两种方式都会出现超卖的现象
        */

        // 测试一把
        SellTicket03 sellTicket03 = new SellTicket03();
        new Thread(sellTicket03).start();  // 第1个线程-窗口
        new Thread(sellTicket03).start();  // 第2个线程-窗口
        new Thread(sellTicket03).start();  // 第3个线程-窗口
    }
}

// 实现接口方式, 使用synchronized实现线程同步
class SellTicket03 implements Runnable {
    private int ticketNum = 100;  // 让多个线程共享 ticketNum
    private boolean loop = true;  // 控制run方法变量
    Object object = new Object();

    // 同步方法(静态的)的锁为当前类本身
    // 解读
    // 1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
    // 2. 如果在静态方法中, 实现一个同步代码块
    /*
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
     */
    public synchronized static void m1() {

    }

    public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }

    // 1. public synchronized void sell() {} 就是一个同步方法
    // 2. 这时锁在 this对象
    // 3. 也可以在代码块上写 synchronize, 同步代码块, 互斥锁还是在this对象
    public /*synchronized*/ void sell() {  // 同步方法, 在同一时刻, 只能有一个线程来执行sell方法
        synchronized (/*this*/object) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }
            // 休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }
    }

    @Override
    public void run() {
        while (loop) {
            sell();  // sell方法是一共同步方法
        }
    }
}

class SellTicket01 extends Thread {
    private static int ticketNum = 100;  // 让多个线程共享 ticketNum

    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }

            // 休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));
        }
    }
}

// 实现接口方式
class SellTicket02 implements Runnable {
    private int ticketNum = 100;  // 让多个线程共享 ticketNum

    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }

            // 休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));
        }
    }
}

3.3、注意事项和细节

在这里插入图片描述

4、线程的死锁

4.1、基本介绍

多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生

4.2、形象的比喻

妈妈:你先完成作业,才让你玩手机
小明:你先让我玩手机,我才完成作业

4.3、代码实现

package syn;

public class DeadLock_ {
    public static void main(String[] args) {
        // 模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A 线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B 线程");
        A.start();
        B.start();

        // 控制台输出
        /*
            A 线程 进入 1
            B 线程 进入 3
         */
    }
}

// 线程
class DeadLockDemo extends Thread {
    static Object o1 = new Object();  // 保证多线程, 共享一个对象,这里使用 static
    static Object o2 = new Object();
    boolean flag;

    public DeadLockDemo(boolean flag) {  // 构造器
        this.flag = flag;
    }

    @Override
    public void run() {
        // 下面业务逻辑的分析
        // 1. 如果 flag 为 T, 线程 A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
        // 2. 如果线程 A 得不到 o2 对象锁, 就会 Blocked
        // 3. 如果 flag 为 F, 线程 B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
        // 4. 如果线程 B 得不到 o1 对象锁,就会 Blocked
        if (flag) {
            synchronized (o1) {  // 对象互斥锁, 下面就是同步代码
                System.out.println(Thread.currentThread().getName() + " 进入 1");
                synchronized (o2) {  // 这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入 2");
                }
            }
        } else {
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName() + " 进入 3");
                synchronized (o1) { // 这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入 4");
                }
            }
        }
    }
}

5、释放锁

5.1、下面操作会释放锁

在这里插入图片描述

5.2、下面操作不会释放锁

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 13:44:53  更:2022-01-01 13:46:31 
 
开发: 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 7:19:17-

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