【多线程】
创始人
2025-05-29 07:01:15
0

多线程

        • 多线程
          • 1.守护线程
          • 2.线程的生命周期
          • 3.线程同步机制
          • 4.互斥锁
          • 5.线程死锁
          • 6.释放锁

多线程

1.守护线程

用户线程:也称为工作线程

守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程也自动结束

常见的守护线程:垃圾回收机制

public class ThreadMethod03 {public static void main(String[] args) throws InterruptedException {MyDaemonThread myDaemonThread = new MyDaemonThread();// 如果我们希望main线程结束后,子线程自动结束// TODO:需要将子线程设为守护线程即可myDaemonThread.setDaemon(true);myDaemonThread.start();for (int i = 1; i <= 10; i++) {System.out.println("宝强在辛苦的工作~~~" + i);Thread.sleep(1000);}System.out.println("主线程结束!!!");}
}class MyDaemonThread extends Thread {@Overridepublic void run() { // 无限循环for (int i = 1; ; i++) {try {Thread.sleep(1000); // 休眠50毫秒} catch (InterruptedException e) {e.printStackTrace();}System.out.println("马蓉和宋哲快乐聊天,哈哈哈~~~~" + i);}}
}
2.线程的生命周期
  • new

  • runnable 可运行的由内核进行调度

    • ready 就绪状态
    • running 运行状态
  • blocked

  • terminated 终止状态

  • waiting

  • timed_waiting 超时等待

    1.先进入new状态 2.再进入runnable状态 3.Thread.sleep()可能导致进入time_waiting状态 4.结束进程则进入terminated状态

    public class ThreadState {public static void main(String[] args) throws InterruptedException {T t = new T();System.out.println(t.getName() + " 的状态:" + t.getState());t.start();while (Thread.State.TERMINATED != t.getState()) {System.out.println(t.getName() + " 的状态:" + t.getState());Thread.sleep(1000);}System.out.println(t.getName() + " 的状态:" + t.getState());}
    }class T extends Thread {@Overridepublic 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;}}
    }
    3.线程同步机制
    1. 在多线程中 保证数据在任何一个时刻 最多由一个线程访问

    2. 当有一个线程对内存进行操作时,其他线程都不能对这个内存地址进行操作

    实现线程同步的具体方法: Synchronized

    1. 同步代码块
    synchronized (对象){  // 对象锁// 需要被同步的代码
    }
    
    1. 放在方法声明中 方法成为同步方法
    pulbic synchronized void m(){// 需要被同步的代码
    }
    

    未使用同步机制售票导致 超卖

    public class SellTicket {public static void main(String[] args) {SellTicketThread sellTicketThread01 = new SellTicketThread();SellTicketThread sellTicketThread02 = new SellTicketThread();SellTicketThread sellTicketThread03 = new SellTicketThread();sellTicketThread01.start();sellTicketThread02.start();sellTicketThread03.start();}
    }class SellTicketThread extends Thread {private static int ticketNum = 100;@Overridepublic void run() {while (true) {if (ticketNum <= 0) {System.out.println("窗口: " + Thread.currentThread().getName() + "售票结束!!!");break;}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("窗口" + Thread.currentThread().getName() + ":售出一张票" + ",剩余" + (--ticketNum) + "张");}}
    }

    上述方法存在超卖问题:

    使用synchronzied 解决超卖问题

    public class SellTicket {public static void main(String[] args) {SellTicketThread02 sellTicketThread02 = new SellTicketThread02();new Thread(sellTicketThread02).start();new Thread(sellTicketThread02).start();new Thread(sellTicketThread02).start();}
    }class SellTicketThread02 implements Runnable {private int ticketNum = 100;private boolean loop = true; // 控制run() 的执行public synchronized void sell() { // 同步方法,在同一时刻,只能有一个线程来执行sell方法if (ticketNum <= 0) {System.out.println("窗口: " + Thread.currentThread().getName() + "售票结束!!!");loop = false;return;}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("窗口" + Thread.currentThread().getName() + ":售出一张票" + ",剩余票数=" + (--ticketNum) + "张");}@Overridepublic void run() {while (loop) {sell();  // sell方法是一个同步方法}}
    }

    效果如下

4.互斥锁
  1. java中引进了对象互斥锁来共享数据操作的完整性
  2. 对象使用互斥锁标记 保证任意时刻只能有一个线程访问该对象
  3. synchronized关键字与互斥锁联系
  4. 同步的局限性:导致程序执行效率降低
  5. 同步方法(静态):当前类.class
  6. 同步方法(非静态):可以是this,也可以是其他对象(要求是同一个对象)

synchronized 同步代码块

public void sell() { 
synchronized  (this)  {if (ticketNum <= 0) {System.out.println("窗口: " + Thread.currentThread().getName() + "售票结束!!!");loop = false;return;}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("窗口" + Thread.currentThread().getName() + ":售出一张票" + ",剩余票数=" + (--ticketNum) + "张");}
}
public synchronized static void m1() {
} //锁加在当前类public static void m2() {
synchronized (SellTicketThread02.class) {System.out.println("m2");
}
}

静态同步方法,锁在当前类

5.线程死锁

多个线程都占用了对方的锁资源,但不肯相让,导致死锁

如:妈妈让小明完成作业后,再玩手机

​ 小明要先玩手机,再写作业

/*** 模拟线程死锁*/
public class DeadLock {public static void main(String[] args) {// 模拟死锁现象DeadLockDemo A = new DeadLockDemo(true);DeadLockDemo B = new DeadLockDemo(false);A.setName("线程A");B.setName("线程B");A.start();B.start();}
}class DeadLockDemo extends Thread {static Object o1 = new Object(); // static 保证多线程共享一个对象static Object o2 = new Object();boolean flag;public DeadLockDemo(boolean flag) {this.flag = flag;}@Overridepublic void run() {// 业务逻辑分析// 1. flag 为 true , 线程A先得到o1对象锁,然后尝试去获取o2对象锁// 2. 线程A 得不到o2 对象锁,就会blocked// 3. flag 为 false , 线程B先得到o2对象锁,然后尝试去获取o1对象锁// 2. 线程B 得不到o1 对象锁,就会blockedif (flag) {synchronized (o1) {  // 对象互斥锁 下面是同步代码System.out.println(Thread.currentThread().getName() + " 进入1");synchronized (o2) {System.out.println(Thread.currentThread().getName() + " 进入2");}}} else {synchronized (o2) {System.out.println(Thread.currentThread().getName() + " 进入3");synchronized (o1) {System.out.println(Thread.currentThread().getName() + " 进入4");}}}}
}

线程死锁

6.释放锁

释放锁的时机:

  1. 当前线程的同步方法,同步代码块执行结束
  2. 当前线程在同步代码块,同步方法中遇到break,return
  3. 当前线程在同步代码块,同步方法中出现了未处理的Error或Exception,导致异常结束
  4. 当前线程在同步代码块,同步方法中执行了线程对象的wait()方法,当前线程暂停并释放锁

不会释放锁的情况:

  1. 程序调用Thread.sleep(),Thread.yield(),暂停当前线程的执行,不会释放锁
  2. 其他线程调用该线程的suspend()将线程挂起,并不释放锁suspend()和resume()过时了

思考题
家庭作业1

import java.util.Scanner;/***  作业01*/
public class HomeWork01 {public static void main(String[] args) {PrintThread printThread = new PrintThread();ReadThread readThread = new ReadThread(printThread);printThread.start();readThread.start();}
}class PrintThread extends Thread {private boolean loop = true;public void setLoop(boolean loop) {this.loop = loop;}@Overridepublic void run() {while (loop) {System.out.println((int) (Math.random() * 100 + 1));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("Print线程退出!!!");}
}// 需要获取PrintThread
class ReadThread extends Thread {private PrintThread printThread;private Scanner sc = new Scanner(System.in);public ReadThread(PrintThread printThread) {this.printThread = printThread;}@Overridepublic void run() {while (true) {// 接收用户输入System.out.println("请输入你的指令(Q 表示退出):");char key = sc.next().toUpperCase().charAt(0);// 获取输入的第一个字符并转成大写if ('Q' == key) {// 以通知的方式结束PrintThread线程printThread.setLoop(false);System.out.println("Read线程结束!!!");break;}}}
}

家庭作业2

如果将 syschronzied 同步代码块时有Thread.sleep() 导致互斥锁始终被第一个线程Thread-0占有,导致Thread-1超取

@Override
public void run() {while (true) {synchronized (this) {money -= 1000;System.out.println("用户:" + Thread.currentThread().getName() + " 取走1000" + ",余额=" + money);}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (money <= 0) {System.out.println("余额不足,结束取款!!!");break;}}
}

正确做法如下 synchronized 只修饰需要互斥的动作,不修饰进程的sleep 注:synchronized是非公平锁

/***  作业02*/
public class HomeWork02 {public static void main(String[] args) {GetMoney getMoney = new GetMoney();new Thread(getMoney).start();new Thread(getMoney).start();}
}// 多线程共享资源 一般实现 Runnable接口
class GetMoney implements Runnable {private int money = 10000;@Overridepublic void run() {while (true) {if (money <= 0) {System.out.println("用户:" + Thread.currentThread().getName() + " 余额不足,结束取款!!!");break;}synchronized (this) {money -= 1000;System.out.println("用户:" + Thread.currentThread().getName() + " 取走1000" + ",余额=" + money);}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

相关内容

热门资讯

原创 腊... 导读:腊肉处理,第一步先泡水还是先煮?大厨教你做法,简单易学真好吃 腊肉作为中国传统美食,承载着深厚...
2025重庆美食“渝味360碗... 5月29日,以“舌尖渝味·全球共享”为主题的2025重庆美食“渝味360碗”嘉年华在九龙坡区巴国城正...
这样吃粽子=喂胃酸?升糖速度是... 明天就将迎来端午节, 粽子是节日绕不开的美食。 如今, 动辄半斤的大粽子越来越流行。 佳节到来之际,...
端午养生正当时,解锁传统佳节里... “五月五日午,赠我一枝艾。”宋代文天祥的《端午即事》道出了端午传统习俗承载着深厚的文化底蕴。作为中国...
行业龙头微念领航螺蛳粉出海 亮... 日前,2025 SIAL 西雅国际食品展在上海新国际博览中心圆满举办。本届西雅展汇集全球35万件特色...
计算机网络(第九弹) --- ...   传输控制协议 TCP 在整个计算机网络中占有很高的地位, 它会控制着网络上数据的传输过程, 当然...
金融“及时雨”润泽南粤文旅,看... 当开平碉楼在夜色中亮起璀璨灯火,当丹霞山索道载着游客掠过云海,当潮州古城的青石板路迎来熙攘人潮,20...
来大连拍哪儿最好看?指南来了!... 晨报讯(半岛晨报、39度视频记者肖崟崟) 5月29日上午,由大连市委宣传部、大连市文化和旅游局、中山...
Kompex::SQLiteD... 使用Kompex::SQLiteDatabase的时候,发现并没有加密的接口ÿ...
2023年华为认证H12-82... 一、什么是HCIP-Datacom 英文名:HCIP-Datacom-Advanced...
【2023-Pytorch-检... 项目下载地址:YOLOV5交通标志识别检测数据集+代码+模型+...
JavaWeb——Repons... 响应体当中的两种的数据格式:字符和字节 Reponse响应字符数据 演示,在get请...
端午节前夕大明湖 水碧树绿美如... 齐鲁晚报·齐鲁壹点记者 周青先端午节前夕,航拍济南大明湖景区。湖水清澈如玉,湖畔树木葱绿,景色仿佛画...
Python3 内置函数 Python3 内置函数 注意:有些函数与 Python2.x 变化不大࿰...
上海地标和平饭店携手莱佛士焕新... 雅高集团与锦江国际联合宣布,享誉全球的上海地标和平饭店将开启全新华章,于2027年焕新升级为莱佛士品...
非遗川韵・狂欢里约——中国广安... 推介会现场 广安市文化广播电视和旅游局与巴西里约旅行社协会签署合作框架协议 【南美侨报特约记者陈妤...
非洲手机之王,光环不再? 传音控股2025年一季度毛利率下降至19.97%,创近年来新低 投资时间网、标点财经研究员 李路 ...
重庆和成都谁强?重庆创造了3.... 在西部崛起的版图上,重庆与成都的发展路径差异鲜明。 重庆以直辖市的战略地位和庞大经济体量稳居西部龙头...
41 openEuler搭建F... 文章目录41 openEuler搭建FTP服务器-传输文件41.1 概述41.2 连接服务器41.3...
小白学Pytorch系列--T... 小白学Pytorch系列–Torch API (10) BLAS and LAPACK Opera...