Java多线程~谈谈自己对于synchronized、volatile关键字的理解,线程的状态转换以及创建线程的方式
迪丽瓦拉
2025-05-29 22:27:38
0

目录

创建线程的方式

继承Thread类

实现Runnable接口 

实现Callable接口

线程的状态转换

volatile关键字

synchronized关键字

synchronized关键字的特性

synchronized原理


创建线程的方式

在java中,创建线程就是new一个Thread,有三种方式,第一种是继承Thread类、第二种是实现Runnable接口、第三种是实现Callable接口

继承Thread类

继承Thread类,重写run方法(run方法即定义要执行的任务代码)

public class TestDemo5 {class MyThread extends Thread {@Overridepublic void run() {System.out.println("继承Thread类方式创建线程");}}public static void main(String[] args) {TestDemo5.MyThread thread = new TestDemo5().new MyThread();thread.start();}
}

实现Runnable接口 

首先实现Runnable接口,再重写run方法,之后创建线程时传入创建的runnable对象

public class TestDemo5 {class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("实现Runnable接口方式创建线程");}}public static void main(String[] args) {TestDemo5.MyRunnable myRunnable = new TestDemo5().new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();}
}

实现Callable接口

public class TestDemo6 {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable callable = new Callable() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 1000; i++) {sum += i;}return sum;}};FutureTask futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);t.start();int ret = futureTask.get();System.out.println(ret);}
}

线程的状态转换

线程的状态有六种:NEW(初始状态)、RUNNABLE(可运行态)、WAITING(等待状态)、TIMED_WAITING(超时等待状态)、BLOCKED(阻塞状态)、TERMINATED(终止状态) 

创建一个线程,线程就进入了NEW状态,当调用start方法时,进入RUNNABLE状态,如果调用了wait、join等方法时就进入WAITING、TIMED_WAITING状态,当多个线程竞争同一把锁时,竞争失败的线程进入BLOCKING状态,线程执行完成后,进入TERMINATED状态。

volatile关键字

使用volatile关键字是为了保证线程安全的,当某个线程对共享变量只是读操作而没有写操作时,使用volatile就可以保证线程安全。volatile的作用是保证可见性和有序性,因为读操作本来就具有原子性,因此仅使用volatile就可以保证线程安全。

· volatile能保证内存的可见性

使多个线程对同一个共享变量操作具有可见性

代码在写入volatile修饰的变量时,先改变工作内存中volatile变量的副本值,再将改变后的副本的值从工作内存刷新到主内存。

代码在读取volatile修饰的变量时,先从主内存中读取volatile变量的最新值到线程的工作内存中,再从工作内存中读取volatile变量的副本。

· volatile可以禁止代码指令重排序,建立内存屏障

例如:小李对自己的安排是:

1、打篮球;

2、吃饭;

3、取快递

如果不加volatile,小李的执行顺序可能是2、1、3或3、2、1等等,但是加上volatile就是1、2、3,这就是禁止指令重排序的作用。

· 但是volatile不能保证原子性

synchronized关键字

多个线程使用同一个对象进行加锁(基于对象头加锁),可以实现线程间的同步互斥。简单地说,它的原理就是基于对象头加锁,满足原子性、可见性、有序性

synchronized关键字的特性

①互斥:

synchronized会起到互斥效果,某个线程执行到某个对象的synchronized中时,如果其他线程也执行到同一个的对象的synchronized就会阻塞等待,进入synchronized代码块相当于加锁,退出synchronized修饰的代码块相当于释放锁。synchronized的锁是存在Java对象头中的。

互斥可以满足原子性,某个线程执行同一个对象加锁的同步代码,排斥另一个线程加锁,满足最小执行单位。

②刷新内存:

synchronized结束释放锁,会把工作内存中的数据刷新到主存,其他线程申请锁,获取的始终是最新数据(满足可见性)。synchronized的工作过程:获得互斥锁->从主内存中拷贝变量的最新副本到工作内存->执行代码->将更改后的共享变量的值刷新到主内存->释放互斥锁

③有序性:

某个线程执行一段同步代码,不管如何重排序,期间都不可能有其他线程指令的执行,这样多个线程执行同步代码,就是满足一定的顺序的

④可重入:

同一个线程可以多次申请同一个对象锁

synchronized原理

结合锁策略,谈synchronized锁的基本特点:

①开始时是乐观锁,如果锁冲突频繁,就转换为悲观锁

②开始时是轻量级锁实现,如果锁被持有的时间较长,就会转为重量级锁

③实现轻量级锁时大概率用到自旋锁策略

④是一种不公平锁

⑤是一种可重入锁

⑥不是读写锁

加锁工作过程:

JVM将synchronized锁分为无锁、偏向锁、轻量级锁、重量级锁状态,会根据情况依次进行升级。

①偏向锁:第一个加锁的线程,优先进入偏向锁状态,偏向锁并不是真的“加锁”,只是给对象头做了一个“偏向锁的标记”,记录这个锁属于哪个线程。如果后续没有其他线程来竞争该锁,就不用进行其他同步操作了,如果后续有其他线程竞争该锁,就取消原来的偏向锁状态,进入一般的轻量级锁。

②轻量级锁:随着其他线程进入竞争,偏向锁的状态被消除,进入轻量级锁状态(自适应的自旋锁)。这里的轻量级锁是通过CAS实现的,通过CAS检查并更新一块内存,如果更新成功表示加锁成功,如果更新失败,则认为锁被占用,继续自旋式的等待(并不放弃CPU).自旋操作是一直让CPU进行空转,比较浪费CPU资源。

③重量级锁:当线程冲突进一步激烈,自旋锁不能快速获取到锁状态,就会升级为重量级锁,重量级锁基于系统级别的mutex lock实现,代价非常大,是系统加锁

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...