从零学Java 线程的状态

Java 线程的状态

文章目录

  • Java 线程的状态
    • 线程的基础状态
    • 1 常见方法
      • 1.1 休眠
      • 1.2 放弃
      • 1.3 加入
      • 1.4 优先级
      • 1.5 线程打断
      • 1.6 守护线程
      • 1.7 线程的状态 - 等待
    • 2 线程安全问题
      • 2.1 线程同步: 同步代码块
      • 2.2 线程同步: 同步方法
      • 2.3 同步规则
      • 2.4 线程的状态 - 阻塞
      • 2.5 特殊现象: 死锁

线程的基础状态

在这里插入图片描述

初始状态(New) : 线程对象被创建,即为初始状态。只在堆中开辟内存,与常规对象无异。

就绪状态(Ready) : 调用start()之后,进入就绪状态。等待OS选中,并分配时间片。

运行状态(Running) : 获得时间片之后,进入运行状态,如果时间片到期,则回到就绪状态。

终止状态(Terminated) : 主线程main()或独立线程run()结束,进入终止状态,并释放持有的时间片。

1 常见方法

1.1 休眠

  • public static void sleep(long millis)
  • 当前线程主动休眠 millis 毫秒,不再参与CPU竞争,直达休眠结束。

eg:

public class TestSleep {public static void main(String[] args) {SleepThread s1 = new SleepThread();SleepThread s2 = new SleepThread();s1.start();s2.start();}static class SleepThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

1.2 放弃

  • public static void yield()
  • 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。

eg:

public class TestYield {public static void main(String[] args) {YieldThread y1 = new YieldThread();YieldThread y2 = new YieldThread();y1.start();y2.start();}static class YieldThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);//主动放弃CPUThread.yield();}}}
}

1.3 加入

  • public final void join()
  • 允许其他线程加入到当前线程中。当前线程会阻塞,直到加入线程执行完毕。

内存分析:

在这里插入图片描述

eg:

public class TestJoin {public static void main(String[] args) throws InterruptedException {JoinThread j1 = new JoinThread();j1.start();//把j1加入到主线程中,造成主线程阻塞,直到j1执行完毕j1.join();for (int i = 0; i < 10; i++) {System.out.println("主线程........"+i);}}static class JoinThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

1.4 优先级

  • 线程对象.setPriority(int)
  • 线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多。

eg:

public class TestPriority {public static void main(String[] args) {PriorityThread p1 = new PriorityThread();PriorityThread p2 = new PriorityThread();PriorityThread p3 = new PriorityThread();//线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多p1.setPriority(1);p3.setPriority(10);//优先级设置要在线程开始之前p1.start();p2.start();p3.start();}static class PriorityThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);}}}
}

1.5 线程打断

  • 线程对象.interrupt();
  • 打断线程,被打断线程抛出InterruptedException异常。

eg:

public class TestInterrupt {public static void main(String[] args) {InterruptThread thread = new InterruptThread();thread.start();System.out.println("10秒内输入任意字符打断子进程休眠");Scanner input = new Scanner(System.in);input.next();thread.interrupt();}static class InterruptThread extends Thread{@Overridepublic void run() {System.out.println("子线程开始休眠...");try {Thread.sleep(10000);System.out.println("正常醒来");} catch (InterruptedException e) {System.out.println("被打醒了");}}}
}

1.6 守护线程

  • 线程有两类:用户线程(前台线程)、守护线程(后台线程)。
  • 如果程序中所有前台线程都执行完毕了,后台线程会自动结束。
  • 垃圾回收器线程属于守护线程。
  • setDaemon(true)设置为守护线程。

eg:

public class TestDaemon {public static void main(String[] args) throws InterruptedException {DaemonThread daemonThread = new DaemonThread();//设置守护线程daemonThread.setDaemon(true);//默认false,关闭daemonThread.start();for (int i = 0; i < 10; i++) {System.out.println("主线程...."+i);Thread.sleep(1000);}}static class DaemonThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

1.7 线程的状态 - 等待

在这里插入图片描述


2 线程安全问题

在这里插入图片描述

需求:A线程将“Hello”存入数组;B线程将“World”存入数组。

线程不安全

  • 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
  • 临界资源:共享资源,一次仅允许一个线程使用,才可保证其正确性。
  • 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。

2.1 线程同步: 同步代码块

同步:一个线程接着一个线程等待执行。异步:多个线程并发同时执行。

语法:

同步代码块:
synchronized(锁对象){ //使用共享资源对象加锁//同步代码(原子操作)
}

eg:

4个窗口共卖1000张票

Ticket:

public class Ticket implements Runnable{private int count = 1000; //票数@Overridepublic void run() {while (true) {//一般选择共享资源synchronized (this) { //锁, 任何引用类型的对象都可以作为锁,但要保证唯一性if (count<=0) {break;}System.out.println(Thread.currentThread().getName() +"卖了第" + count + "张票");count--;}}}
}

Test:

public class Test {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(ticket,"窗口1").start();new Thread(ticket,"窗口2").start();new Thread(ticket,"窗口3").start();new Thread(ticket,"窗口4").start();}
}

注意:

  1. 任何的引用类型对象都可以作为锁,但是保证多个线程使用唯一对象,一般使用共享资源作为锁。
  2. 每个对象都有一个互斥锁标记,用来分配给线程的,只有拥有对象互斥锁标记的线程,才能进入同步代码
  3. 线程退出同步代码块时,会释放相应的互斥锁标记。

2.2 线程同步: 同步方法

语法:

同步方法:
synchronized 返回值类型 方法名称(形参列表){ //对当前对象(this)加锁// 代码(原子操作)
}

eg:

4个窗口共卖1000张票

Ticket:

public class Ticket implements Runnable{private int count = 1000;@Overridepublic void run() {while (true) {if (!sale()) {break;}}}//同步方法public synchronized boolean sale() {if (count<=0) {return false;}System.out.println(Thread.currentThread().getName() +"卖了第" + count + "张票");count--;return true;}
}

注意:

  1. 只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步方法中
  2. 线程退出同步方法时,会释放相应的互斥锁标记。
  3. 如果当前方法是非静态方法锁是"this",如果方法是静态方法锁是"类名.class"

2.3 同步规则

注意

  • 只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记。
  • 如调用不包含同步代码块的方法,或普通方法时,则不需要锁标记,可直接调用。

已知JDK中线程安全的类

  • StringBuffer
  • Vector
  • Hashtable
  • 以上类中的公开方法,均为synchonized修饰的同步方法。

eg:

你和你女朋友共用一张银行卡,你向卡中存钱,你女朋友从卡中取钱,使用程序模拟过程?

BankCard:

public class BankCard {private double money;public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}
}

Test:

public class Test {public static void main(String[] args) {BankCard card = new BankCard();//匿名内部类Runnable save = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {synchronized (card) {card.setMoney(card.getMoney() + 1000);System.out.println(Thread.currentThread().getName()+"存了1000, 余额为"+card.getMoney());}}}};//匿名内部类Runnable take = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {synchronized (card) {if (card.getMoney() >= 1000) {card.setMoney(card.getMoney() - 1000);System.out.println(Thread.currentThread().getName()+"取了1000, 余额为"+card.getMoney());} else {System.out.println("赶紧存钱...");i--;}}}}};new Thread(save,"小明").start();new Thread(take,"小红").start();}
}

2.4 线程的状态 - 阻塞

在这里插入图片描述

注:JDK5之后就绪、运行统称Runnable

2.5 特殊现象: 死锁

死锁:

  • 当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁。
  • 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。

eg:

吃饭问题

Test:

public class TestDeadLock {public static void main(String[] args) {new Boy().start();new Girl().start();}static class Lock {static Object LockA = new Object();static Object LockB = new Object();}static class Boy extends Thread {@Overridepublic void run() {synchronized (Lock.LockA) {System.out.println("Boy拿到了A锁");synchronized (Lock.LockB) {System.out.println("Boy拿到了B锁");System.out.println("Boy可以吃饭了");}}}}static class Girl extends Thread {@Overridepublic void run() {synchronized (Lock.LockB) {System.out.println("Girl拿到了B锁");synchronized (Lock.LockA) {System.out.println("Girl拿到了A锁");System.out.println("Girl可以吃饭了");}}}}
}

情况一: 死锁

Boy拿到了A锁
Girl拿到了B锁

情况二: 未死锁

Boy拿到了ABoy拿到了BBoy可以吃饭了
Girl拿到了BGirl拿到了AGirl可以吃饭了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新版网易滑块

突然发现脸皮厚根本没用&#xff0c;大冬天的&#xff0c;风吹过来还是会冷。 大哥们多整件衣裳&#xff0c;好冷&#xff01;&#xff01;&#xff01;&#xff01; 网易更新了&#xff0c;这俩 dt跟f值。 dt为 这里返回的&#xff0c;忽略掉他。 data参数中的d值&#xff…

未来气膜体育馆的发展趋势是什么?

未来气膜体育馆的发展趋势是多方面的&#xff0c;以下是其中几个方面的趋势。 起初&#xff0c;随着人们对体育运动的需求不断增加&#xff0c;气膜体育馆的建设和使用将成为一种趋势。气膜体育馆具有灵活性和可移动性的特点&#xff0c;可以快速搭建和拆除&#xff0c;能够适…

低代码平台,新型应用程序开发神器

目前低代码平台如火如荼。这一新兴技术为企业提供了一种高效、灵活、快速开发应用程序的方法&#xff0c;并在短时间内取得了巨大成功。然而&#xff0c;我们不得不面对低代码平台的优劣以及其所带来的挑战。本文将深入探讨低代码平台在不同情况下的优劣势&#xff0c;并与您分…

AI能否真的取代程序员?

一个Java程序员从接到需求到最终开发完功能的流程大致如下 首先是理解原型图&#xff0c;设计表结构根据表结构编写增删改查代码与前端联调&#xff0c;完成功能开发 那么以上步骤AI能不能完成呢&#xff1f; 让我们试一下&#xff1a; 第一步&#xff0c;使用 AI助手 解析流…

设计模式之状态模式【行为型模式】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某…

postman环境变量全局变量设置

postman环境变量、全局变量设置 在公司中&#xff0c;一般会存在开发环境、测试环境、线上环境等&#xff0c;如果需要在不 同的环境下切换做接口测试&#xff0c;显然我们需要把所有接口的域名进行修改&#xff0c;如果接 口测试用例较多&#xff0c;那么修改会非常费力&…

Redis基础系列-哨兵模式

Redis基础系列-哨兵模式 文章目录 Redis基础系列-哨兵模式1. 引言2. 什么是哨兵模式&#xff1f;3. 哨兵模式的配置4. 哨兵模式的启动和验证4.1 主master宕机&#xff0c;看会出现什么问题4.2 重启6379主机 5. 哨兵模式的工作原理和选举原理5.1. SDown主观下线&#xff08;Subj…

基于Python实现地标景点识别

目录 前言简介地标景点识别的背景 地标景点识别的原理卷积神经网络&#xff08;CNN&#xff09;的基本原理地标景点识别的工作流程 使用Python实现地标景点识别的步骤数据收集数据预处理构建卷积神经网络模型模型训练 参考文献 前言 简介 地标景点识别是一种基于计算机视觉技术…

Qt SDL2播放Wav音频

这里介绍两种方法来实现Qt播放Wav音频数据。 方法一&#xff1a;使用QAudioOutput pro文件中加入multimedia模块。 #include <QApplication> #include <QFile> #include <QAudioFormat> #include <QAudioOutput>int main(int argc, char *argv[]) {…

欧姆龙plc学习NJ系列CJ系列资料Sysmac Studio编程软件视频教程

Sysmac Studio是欧姆龙公司开发的一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于编程和配置欧姆龙PLC&#xff08;可编程逻辑控制器&#xff09;和其他自动化设备。Sysmac Studio支持以下型号的欧姆龙PLC&#xff1a;1. NJ系列&#xff1a;NJ501、NJ301、NJ101、…

【算法】算法(模拟、指针等)解决字符串类题目(C++)

文章目录 1. 前言2. 解决 字符串类算法题14.最长公共前缀5.最长回文子串67.二进制求和43.字符串相乘 1. 前言 字符串题目有很多种&#xff0c;这里筛选几个考察模拟、双指针等的题目&#xff0c;并用相关算法解决。 2. 解决 字符串类算法题 14.最长公共前缀 思路 题意分析&…

【固态钽表面贴装电容】 MIL-PRF-55365 美军标

钽电解电容器是体积效率、电气参数稳定、高可靠性和长使用寿命是主要考虑因素的应用的首选。 钽/氧化钽/二氧化锰系统的稳定性和对高温的耐受性使固体钽消泡器成为当今表面贴装组装技术的合适选择。 钽不是纯净状态的。 相反&#xff0c;它通常存在于许多氧化物矿物中&#xf…

编曲混音FL Studio21.2对电脑有什么配置要求

FL Studio 21是一款非常流行的音乐制作软件&#xff0c;它可以帮助音乐人和制作人创作出高质量的音乐作品。然而&#xff0c;为了保证软件的稳定性和流畅性&#xff0c;用户需要知道FL Studio 21对电脑的配置要求。本文将介绍FL Studio 21的配置要求&#xff0c;以帮助用户选择…

SQL基础知识4

一、内置函数 1、数值函数 1.1基本函数 1.2时间函数 二、存储过程 1、概述 2、分类 3、创建 4、总结 多了很多传递参数 三、存储函数 说明定义 例子 案例1 方法一 方法二 案例2 例子3 对比 复习

【贪心】受标签影响的最大值

/** 贪心&#xff1a;要想使子集分数最大&#xff0c;应选取values中较大的值。* 思路&#xff1a;使用一个哈希表来记录每个标签使用的次数&#xff0c;相同标签使其不超过useLimit限制* 对values进行降序排序&#xff0c;并对其进行遍历只要标签使用次数不超过限制就…

住宅IP和数据中心IP有何区别?为什么住宅IP更适合爬虫采集?

随着互联网的普及和发展&#xff0c;IP地址作为网络通信中的重要标识&#xff0c;其类型和应用场景也在不断变化。其中&#xff0c;住宅IP和数据中心IP是两种常见的IP类型&#xff0c;它们在某些方面存在明显的区别。本文将探讨这两种IP类型的区别以及为什么住宅IP更适合爬虫采…

python GUI开发:实现主屏幕控制副屏显示

实现效果 实现代码 import tkinter as tk import threading import pygetwindow as gw import subprocess import cv2 import pygame import time import screeninfodef func1():print("影音播放")open_child_window()def func5():print("视频播放")video…

数据库系列:InnoDB下实现高并发控制

1 介绍 并发控制是为了防止多用户并发使用数据库时造成数据错误和程序运行错误&#xff0c;保证数据的完整性。当多个事务并发地存取数据库时&#xff0c;就会产生同时读取和/或修改同一数据的情况。若对并发操作不加控制就可能会存取和存储不正确的数据&#xff0c;破坏数据库…

web前端(第二次作业)

1、计算用户指定的数值内的奇数和。例如用户输入的是 10&#xff0c;则计算 1 3 5 7 9 的和 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><script>var nprompt("请输入数值&#xff1a;&…

基于开源组件自主开发工作流引擎系统

目前基于Java语言开发的主流开源工作流引擎有osworkflow、jbpm、activiti、flowable、camunda。其中osworkflow、jbpm技术较老已经过时&#xff0c;activiti包括activiti5、activiti6、activiti7三个版本&#xff0c;flowable分开源版和商业版&#xff0c;camunda包括camunda7和…