JUC专题——Java并发基础

本文部分内容节选自《Java并发编程的艺术》

线程

现代操作系统调度的最小单元是 线程 , 也叫 轻量级进程 . 一个进程里可以创建多个线程, 线程拥有各自的计数器, 堆栈和局部变量, 并且能够访问共享的内存变量

线程优先级

现代操作系统使用时分的形式调度运行的线程, 操作系统会分出一个个时间片, 线程会分配到若干时间片, 当线程的时间片用完了就会发生线程调度, 并等待下次分配. 时间片多少决定了线程使用处理器资源的多少, 而线程优先级就是决定线程需要多或者少分配一些处理器资源的线程属性

在 Java 线程中, 通过整型成员变量 priority 控制优先级, 优先级的范围是 1~10, 线程构建时可以通过 setPriority() 方法来修改优先级, 默认的优先级为 5. 优先级高的线程分配时间片的数量要多于优先级低的线程.

设置优先级时, 对于频繁阻塞(休眠或 I/O操作) 的线程需要设置较高优先级, 对于偏重计算的线程需要设置较低的优先级, 确保处理器不会被独占.

在不同JVM和不同操作系统上, 线程规划会存在差异, 有的操作系统会忽视对线程优先级的设定

线程状态

Java 线程在生命周期中可能处于如下的6种状态. 在给定的任意时刻, 线程只能处于其中一个状态

名称说明
NEW线程被创建, 但是没有调用 start() 方法
RUNNABLE允许状态, Java 线程将操作系统中就绪和运行两种状态笼统地称为 “运行中”
BLOCKED阻塞状态, 表示线程被锁阻塞
WAITING等待状态, 表示线程进入等待状态, 进入该状态表示当前线程需要等待其他线程做出特定动作
TIME_WAITING超时等待, 该状态不同于WAITING, 它是可以在指定的时间自行返回的
TERMINATED终止状态, 线程已经执行完毕

线程创建之后, 调用 start() 方法开始运行, 执行 wait() 方法, 线程进入等待状态, 进入等待状态的线程需要依靠其他线程的通知才能回到运行状态, 而超时等待状态相当于在等待状态的基础上增加了超时限制, 也就是超时时间到达时会自动恢复到运行状态. 当线程调用同步方法时, 在没有获取到锁的情况下, 线程会进入阻塞状态. 线程在执行 Runnablerun() 方法之后会进入到终止状态

Daemon线程

Daemon线程是一种支持型线程, 因为它主要被用作程序中后台调度和支持性工作. 这意味着, 当一个JVM中不存在非Daemon线程时, JVM会退出

可以通过 ThreadThread.setDaemon(true) 将一个线程设置为 Daemon线程

必须在启动线程之前就设置好这个线程是否是Daemon线程, 不能在启动之后再设置, 否则会报错

启动和终止线程

构建线程

在运行线程之前要构造一个线程对象, 线程对象在构造时候需要提供线程所需要的属性, 如线程所属的线程组, 优先级, 是否为Daemon线程等信息

启动线程

线程对象在初始化完成之后, 调用 start() 方法就能启动线程.

中断

中断表示一个运行中的线程是否被其他线程进行了终端操作. 其他线程通过调用该线程的 interrupt() 方法对其进行中断操作

线程通过检查自身是否被中断来进行响应, 线程通过方法 inInterrupted() 来进行判断是否被中断, 也可以调用静态方法 Thread.interrupted() 对当前线程的中断标记位进行复位.

终止线程

中断操作是一种简便的线程间交互方式, 且这种交互方式最适合用来取消或停止任务. 除了中断以外, 还可以利用一个boolean变量来控制是否需要停止任务并终止该线程

线程间通信

volatile 和 synchronized

关键字 volatile 可以用来修饰字段, 告知程序任何对该变量的访问均需要从共享内存获取, 而对于它的改变必须刷新回到共享内存, 它能保证所有线程对变量访问的可见性

关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用, 它主要保证多个线程在同一时刻只有一个线程处于方法或同步代码块中, 保证线程对变量访问的可见性和排他性

等待/通知机制

一个线程修改了一个对象的值, 而另一个线程感知到了变化, 然后进行相应的操作, 整个过程开始于一个线程, 而最终执行又是另一个线程.

Java 通过内置的 等待/通知 机制解决了这个问题

等待/通知机制是所有Java对象都具备的, 因为这些方法被定义在 java.lang.Object 内部

方法名称描述
notify()通知一个在对象上等待的线程, 使其从 wait() 方法返回, 返回的前提是该线程拿到了对象的锁
notifyAll()通知所有等待在该对象上的线程
wait()调用该方法的线程进入 WAITING 状态, 只有等待另外线程的通知或者被中断才会返回, 需要注意, 调用 wait() 方法之后, 会释放对象的锁
wait(long)超市等待一段时间, 这里的参数单位是毫秒
wait(long, int)对于超时时间更细粒度的控制, 可以精确到纳秒

等待/通知机制, 是指一个线程 A 调用了对象 O 的 wait() 方法进入等待状态, 而另一个对象 B 调用了对象 O 的 notify() 或者 notifyAll() 方法, 线程 A 收到通知后从对象 O 的 wait() 方法返回, 进而执行后续操作. 上述两个线程通过对象 O 完成交互, 而对象上的 wait()notify()/notifyAll() 就像是开关信号一样, 用来完成等待方和通知方之间的交互工作

使用 wait()notify() / notifyAll() 需要注意的细节

  1. 使用 wait() , notify()notifyAll() 时需要先对调用对象加锁
  2. 调用 wait() 方法后, 线程状态由 RUNNING 变为 WAITING, 并将当前线程放置到对象的等待队列
  3. notify()notifyAll() 方法调用之后, 等待线程仍然不会从 wait() 返回, 需要调用 notify()notifyAll() 的线程释放锁之后, 等待线程才有机会从 wait() 返回
  4. notify() 方法将等待队列中的一个等待线程从等待队列中移到同步队列中, 而 notifyAll() 方法则是将等待队列中所有的线程全部移到同步队列, 被移动的队列状态由 WAITING 变为 BLOCKED
  5. wait() 方法返回的前提是获得了调用对象的锁

管道输入/输出流

管道输入/输出流主要用于线程之间的数据传输, 而传输的媒介是内存

管道输入/输出流有四种实现: PipedOutputStream, PipedInputStream, PipedReader, PipedWriter, 前两种面向字节, 后两者面向字符

Thread.join() 的使用

如果一个线程 A 执行了 thread.join() 语句, 其含义是: 当前线程 A 等待thread线程终止之后才从 thread.join() 返回. 线程 Thread 除了提供 join() 方法之外, 还提供了 join(long millis)join(long millis, int nanos) 两个具备超时特性的方法. 这两个超时方法表示如果线程thread在给定的超时时间内没有终止, 那么将会从超时方法中返回

ThreadLocal 的使用

ThreadLocal, 即线程变量, 是一个以 ThreadLocal对象为键, 任意对象为值的存储结构, 这个结构被携带在线程上, 也就是说一个线程可以根据一个 ThreadLocal 对象查询到绑定在这个线程上的一个值

可以通过 set(T) 方法来设置一个值, 在当前线程下可以通过 get() 方法获取到原先设置的值

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

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

相关文章

lua 光速入门

文章目录 安装注释字符串变量逻辑运算条件判断循环函数Table (表)常用全局函数模块化 首先明确 lua 和 js Python一样是动态解释性语言,需要解释器执行。并且不同于 Python 的强类型与 js 的弱类型,它有点居中,倾向于强类型。 安装 下载解释…

【OpenHarmony】TDD-FUZZ环境配置

零、参考 1、AttributeError: ‘ElementTree‘ object has no attribute ‘getiterator‘:https://blog.csdn.net/suhao0911/article/details/110950742 一、创建工作目录 1、新建工作目录如:D:\0000_TDD_FUZZ\0000_ohos_tdd_fuzz。 2、gitee上下载 t…

陇剑杯 ios 流量分析 CTF writeup

陇剑杯 ios 流量分析 链接:https://pan.baidu.com/s/1KSSXOVNPC5hu_Mf60uKM2A?pwdhaek 提取码:haek目录结构 LearnCTF ├───LogAnalize │ ├───linux简单日志分析 │ │ linux-log_2.zip │ │ │ ├───misc日志分析 │ │…

html+vue编写分页功能

效果&#xff1a; html关键代码&#xff1a; <div class"ui-jqgrid-resize-mark" id"rs_mlist_table_C87E35BE"> </div><div class"list_component_pager ui-jqgrid-pager undefined" dir"ltr"><div id"pg…

Linux编辑器-vim的使用

vim的基本概念 vim的三种模式(其实有好多模式&#xff0c;目前掌握这3种即可),分别是命令模式&#xff08;command mode&#xff09;、插 入模式&#xff08;Insert mode&#xff09;和底行模式&#xff08;last line mode&#xff09;&#xff0c;各模式的功能区分如下&#…

中医优势病种诊疗方案数据库

中医诊疗方案结合了几千年的实践经验与理论体系&#xff0c;形成了一套独特的诊疗方法。随着国家对中医药事业的重视&#xff0c;多个中医诊疗方案被国家卫生健康委员会和国家中医药管理局等权威机构正式发布&#xff0c;这对规范中医临床诊疗行为&#xff0c;提升医疗服务质量…

富格林:学习甄别暗箱陷阱阻挠受害

富格林悉知&#xff0c;黄金投资在投资市场上扮演着重要的角色&#xff0c;在任何时期总有人在投资黄金。然而&#xff0c;对于新手投资者来说&#xff0c;了解虚假信息防止诱骗暗箱受害是非常关键的&#xff0c;投资者在进入投资市场之前&#xff0c;需要掌握一定的技术要领&a…

MTK MFNR

一、MFNR 简介 二、MFNR 开关与决策 三、MFNR 相关的adb 命令 四、MFNR log 分析 五 参考文献 一、MFNR 简介 MFNR : Multiple Frame Noise Reduction MFLL : Multiple Frame Low Light BSS : Best Select Shot MFNR 跟 MFLL 是两个功能一致&#xff0c;名称不同的简称&#xf…

SAP MESSAGEID FF759 不能过帐凭证:本币计的税基为0的快捷方案

不能过帐凭证:本币计的税基为0 消息编号 FF759 诊断 尝试步成本币中计税基数为零的凭证&#xff0c;尽管外币中税金额和计税基数不为零&#xff0c; 系统响应 拒绝凭证输入。 步骤 再次输入凭证。 这个错误的原因&#xff0c;是因为四舍五入导致的税为零。根据百度的反馈&…

执行npm命令一直出现sill idealTree buildDeps怎么办?

一、问题 今天在运行npm时候一直出项sill idealTree buildDeps问题 二、 解决 1、先删除用户界面下的npmrc文件&#xff08;注意一定是用户C:\Users\{账户}\下的.npmrc文件下不是nodejs里面&#xff09;&#xff0c;进入到对应目录下&#xff0c;Mac启动显示隐藏文件操作&…

生产服务器变卡怎么排查

服务器变卡怎么排查&#xff0c;可以从以下四个方面去考虑 生产服务器变卡怎么排查 1、网络2、cpu的利用率3、io效率4、内存瓶颈 1、网络 可以使用netstat、iftop等工具查看网络流量和网络连接情况&#xff0c;检查是否网络堵塞、丢包等问题 2、cpu的利用率 1、用top命令定…

【arcpy】 解决构建过小面矢量无效

问题描述 通常利用arcpy向面矢量添加面数据的方法如下 import arcpy singlePolygon [[86.30491319444444, 31.08521484375], [86.30491427951388, 31.08521484375], [86.30491427951388, 31.085215928819444], [86.30491319444444, 31.085215928819444],[86.30491319444444,…

python在selenium网页模拟运行过程中需要打开文件夹上传文件的情况的解决方法

在selenium运行过程中&#xff0c;可能会遇到网页需要上传文件图片等情况&#xff0c;有时可以直接用selenium中send_keys直接上传&#xff0c;但是有时不行&#xff0c;这时我们需要用到另一个包&#xff0c;pywinauto 具体的代码如下&#xff0c; import pywinauto # pywina…

JNI NDK错误汇总

问题一&#xff1a;This app only has 32-bit [armeabi-v7a] native libraries. 解决&#xff1a;在app目录下的build.gradle的android结构里加上arm64-v8a&#xff0c;如下&#xff1a; android {.......defaultConfig{ndk{ abiFilters armeabi-v7a, arm64-v8a //abiFilters a…

驱动执行篇之电机编码器:编码器基础与双编码器方案

目录 |1.编码器概述 |2.编码器分类 |2.1.增量式编码器和绝对值编码器 |2.2.光电编码器 |3.双编码器方案 |3.1几种扭矩感知方案 |3.3双编码器安装方式 |1.编码器概述 编码器 编码器&#xff0c;是将信号&#xff08;如比特流&#xff09;或数据进行编制、转换为可用以通讯…

ECA-Net:深度卷积神经网络中的高效通道注意力机制【原理讲解及代码!!!】

ECA-Net&#xff1a;深度卷积神经网络中的高效通道注意力机制 在深度学习领域&#xff0c;特别是在深度卷积神经网络&#xff08;DCNN&#xff09;中&#xff0c;注意力机制已经成为提升模型性能的关键技术之一。其中&#xff0c;ECA模块&#xff08;Efficient Channel Attent…

C# 中优雅的动态序列化接口返回数据

在C#中&#xff0c;与Web服务的交互经常涉及到数据的序列化和反序列化。当我们与不同的API接口交互时&#xff0c;返回的数据结构和类型可能会有所不同。为了处理这种多样性&#xff0c;我们需要一种方法来动态地序列化接口返回的数据。 本文将介绍如何使用C#中的Json.NET&…

前端项目的导入和启动

安装依赖 前端安装依赖只需要在控制台执行“npm i”即可。Tips&#xff1a;当我们执行的时候&#xff0c;有时候会很慢。可以考虑使用yarn或者pnpm。然而使用yarn或者pnpm有时候有一些莫名其妙的问题。所以还是得使用npm&#xff0c; 这个时候可以通过更换镜像源为淘宝镜像源。…

【C++】容器:vector的接口介绍大全

vector的接口介绍大全 一、vector的接口介绍二、常用接口的使用1. 定义vector2. vector赋值操作3. 迭代器4. 容量操作resizereserve 5. 访问元素[] front back at 6. 修改容器assignpush_back pop_backinserteraseclear 7. 容器的其他操作swap vector 是 C 标准模板库&#xff…

B2134 质数的和与积

题目描述: 两个质数的和是 S&#xff0c;它们的积最大是多少&#xff1f; 代码: package lanqiao;import java.math.BigInteger; import java.util.*;public class Main {public static int[] prime new int[10000];public static void main(String[] args) {Scanner sc n…