JAVAEE—Callable接口,ReentrantLock,synchronized的工作过程

文章目录

  • Callable接口的用法
    • Callable与FutureTask类
  • 加锁的工作过程
    • 什么是偏向锁呢?
      • 举个例子
    • 轻量级锁
    • 重量级锁
  • ReentrantLock
    • ReentrantLock 的用法:

Callable接口的用法

Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的方式计算结果.
我们之前写的代码重线程内部的lambda表达式中现实的run方法其内部的返回值是void因此当我们想要返回在方法内部实现返回一个数字的时候都很难做到。而Callbale就解决了这个方法
在这里插入图片描述

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Main {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer>callable=new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum=0;for(int i=1;i<=100;i++){sum+=i;}return sum;}};FutureTask<Integer>futureTask=new FutureTask<>(callable);Thread thread=new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}

Callable与FutureTask类

请看上面的callbale接口的运用。我们可以看到这个接口中我们实现了一个call方法他的返回值是一个Integer,这里call方法是我们的核心方法我们看一下源代码在这里插入图片描述
我们发现这个源代码中其实也就只用一个call方法这个方法的返回类型是一个模板也就是说他的返回类型我们可以进行指定,因此我们这里实例处的类型是什么这里的返回值就是什么。
那么我们如何创建线程吗?是直接用实例出的对象作为new Thread()括号中的参数吗?
很明显不是如此我们需要一个中间类那就是FutureTask那么我们来看一下这里面的源代码熟悉一下继承关系
在这里插入图片描述

首先我们可以看到这个类继承了一个RunnableFuture这个类,我们不知道这个类是什么但是我们可以继续看源代码。
在这里插入图片描述

我们发现这个类继承Runnable然后我们再去想一下Thread的构造方法,是可以接受Runnable类的因此我们知道此时也可以接受这个FutureTask类而这个FutureTask类里面的构造函数有一个方法
在这里插入图片描述
我们可以知道FutureTask类可以接受callable类并且其内部就有一个Callable类。

加锁的工作过程

加锁的工作过程就是下面的这个过程
在这里插入图片描述
在刚开始的时候是无锁的一个状态。当第一个尝试加锁的进程出现的时候会进入偏向锁的状态。那么什么是偏向锁呢?

什么是偏向锁呢?

偏向锁你可以理解为钓鱼,因为偏向锁其实并不是真的加锁,而是加了一个标记记录这个锁属于哪个线程,但是此时并没有加锁,那么当出现另一个线程也去申请这个锁的时候,那么第一个线程才会对其加锁。偏向锁本质上相当于 “延迟加锁” . 能不加锁就不加锁, 尽量来避免不必要的加锁开销. 但是该做的标记还是得做的, 否则无法区分何时需要真正加锁.

举个例子

相当于有一个帅哥叫做小帅,
他勾搭上了一个美女叫做小美
但是他很享受这个暧昧的过程因此不愿意和小美捅破那层窗户纸
此时当又有一个帅哥出现和他一起竞争小美
这时候小帅就慌了他会火速与小美表白这时候由于小美和小帅呆的时间长因此小美会优先同意小帅的表白。
这就是一个偏向锁。


这时候就会进入下一个状态那就是轻量级锁

轻量级锁

随着其他线程进入竞争, 偏向锁状态被消除, 进入轻量级锁状态(自适应的自旋锁).
此处的轻量级锁就是通过 CAS 来实现.

通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
如果更新成功, 则认为加锁成功
如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU).

当锁竞争激烈起来之后将会进入重量级锁状态

重量级锁

如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会膨胀为重量级锁此处的重量级锁就是指用到内核提供的 mutex .

执行加锁操作, 先进入内核态.
在内核态判定当前锁是否已经被占用
如果该锁没有占用, 则加锁成功, 并切换回用户态.
如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.
经历了一系列的沧海桑田, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒
这个线程, 尝试重新获取锁.

ReentrantLock

这个的意思很明显就是可重入锁,可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全.

ReentrantLock 也是可重入锁. “Reentrant” 这个单词的原意就是 “可重入”

ReentrantLock 的用法:

lock(): 加锁, 如果获取不到锁就死等.
trylock(超时时间): 加锁, 如果获取不到锁, 等待一定的时间之后就放弃加锁.
unlock(): 解锁

从这里我们可以看出来ReentrantLock 其实是一个类,他不是一个关键字是java封装的一个类那么这里面主要的方法就是上面的这三个我们来看一下如何使用

import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;public class test_ReentrantLock {public static void main(String[] args) {ReentrantLock reentrantLock=new ReentrantLock();int n=5;Thread thread=new Thread(new Runnable() {@Overridepublic void run() {reentrantLock.lock();int sum=0;while(sum<n){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}sum++;System.out.println("我是线程1");}reentrantLock.unlock();}});Thread thread2=new Thread(new Runnable() {@Overridepublic void run() {reentrantLock.lock();int sum=0;while(sum<n){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}sum++;System.out.println("我是线程2");}reentrantLock.unlock();}});thread2.start();thread.start();}
}

在这里插入图片描述
我们发现这时候打印的结果不会是乱序的说明此时加锁的目的是达到了的,可是这里如果只有这种应用是不是太低级了感觉要不要它无所谓啊。但其实这里面它最不同的就是trylock方法这个方法是很大的不同的。那么我们把代码改一下

import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;public class test_ReentrantLock {public static void main(String[] args) {ReentrantLock reentrantLock=new ReentrantLock();int n=5;Thread thread=new Thread(new Runnable() {@Overridepublic void run() {reentrantLock.tryLock();//第一处改动int sum=0;while(sum<n){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}sum++;System.out.println("我是线程1");}reentrantLock.unlock();}});Thread thread2=new Thread(new Runnable() {@Overridepublic void run() {reentrantLock.lock();int sum=0;while(sum<n){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}sum++;System.out.println("我是线程2");}reentrantLock.unlock();}});thread2.start();try {//第二处改动Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}thread.start();}
}

变成了上面的代码之后我们来观察一下结果。
在这里插入图片描述
我们发现此时的代码变成了乱序的了就像没有加锁一样而事实上确实也没有加锁,因为tryLock其实就是尝试加锁我们的t2线程是先启动的因此是先获取锁的这时候t1线程想要获取锁就获取不到,那么这时候t1线程就说那获取不到我就不获取了直接往下执行了,这就是和synchronized很大的不同之处。
抛出异常的原因是因为我们的t1线程没有获取倒锁但是代码里却有释放锁的代码因此抛出了异常。

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

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

相关文章

Ubuntu20.04使用Neo4j导入CSV数据可视化知识图谱

1.安装JDK&#xff08; Ubuntu20.04 JDK11&#xff09; sudo apt-get install openjdk-11-jdk -y java -version which java ls -l /usr/bin/java ls -l /etc/alternatives/java ls -l /usr/lib/jvm/java-11-openjdk-amd64/bin/java确认安装路径为/usr/lib/jvm/java-11-openjd…

Celery的任务流

Celery的任务流 在之前调用任务的时候只是使用delay()和apply_async()方法。但是有时我们并不想简单的执行单个异步任务&#xff0c;比如说需要将某个异步任务的结果作为另一个异步任务的参数或者需要将多个异步任务并行执行&#xff0c;返回一组返回值&#xff0c;为了实现此…

STL是什么?如何理解STL?

文章目录 1. 什么是STL2. STL的版本3. STL的六大组件4. 如何学习STL5.STL的缺陷 1. 什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 2. …

OpenHarmony实战开发-使用一次开发多端部署实现一多设置典型页面

介绍 本示例展示了设置应用的典型页面&#xff0c;其在小窗口和大窗口有不同的显示效果&#xff0c;体现一次开发、多端部署的能力。 1.本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备&#xff08;或多窗口尺寸&#xff09;适配&#xff0c;保…

WebGIS 之 vue3+vite+ceisum

1.项目搭建node版本在16以上 1.1创建项目 npm create vite 项目名 1.2选择框架 vuejavaScript 1.3进入项目安装依赖 cd 项目名 npm install 1.4安装cesium依赖 pnpm i cesium vite-plugin-cesium 1.5修改vite.config.js文件 import { defineConfig } from vite import vue fr…

RK3568 RTC驱动实验

RK3568 RTC驱动实验 1. RTC简介 ​ RTC 也就是实时时钟&#xff0c;用于记录当前系统时间&#xff0c;对于 Linux 系统而言时间是非常重要的&#xff0c;使用 Linux 设备的时候也需要查看时间。RTC是Linux的时间系统。 ​ RTC 设备驱动是一个标准的字符设备驱动&#xff0c;…

基于Python的微博旅游情感分析、微博舆论可视化系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Python网络爬虫(三):Selenium--以携程酒店为例

1 Selenium简介 Selenium是一个用于网站应用程序自动化的工具&#xff0c;它可以直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。它相当于一个机器人&#xff0c;可以模拟人类在浏览器上的一些行为&#xff0c;比如输入文本、点击、回车等。Selenium支持多种浏览器&…

记录一次官网访问很慢的情况

客户查看云监控,带宽未超限,客户取的是1分钟的原生值,也就是1分钟也是个平均值。 但是客户的原始值&#xff0c;其实就是1分钟内的平均值。所以客户的瞬时超限&#xff0c;其实是看不出来的。但是后端同事从实时监控里面可以看到超限的情况。 客户升带宽后&#xff0c; 发现还…

Flutter 应用数据持久化指南

1. 介绍 1.1 什么是数据持久化&#xff1f; 数据持久化是指将应用程序中的数据保存在持久存储介质&#xff08;如硬盘、数据库等&#xff09;中的过程。在计算机科学领域&#xff0c;持久化数据是指数据在程序退出或系统关机后仍然存在的能力。这种持久性使得数据可以在不同的…

是德科技keysight 33621A波形发生器

181/2461/8938产品概述&#xff1a; 与上一代DDS波形发生器相比&#xff0c;采用独家Trueform技术的安捷伦HP 33621A波形发生器具有更高的性能、保真度和灵活性。安捷伦HP 33621A 120 MHz、单通道、Trueform arbs&#xff0c;带时序控制和64 MSa存储器&#xff0c;1 ps抖动&am…

go juc 线程中的子类

1.go test() 主死随从 package mainimport ("fmt""strconv""time" )func test() {for i : 1; i < 10; i {fmt.Println("hello " strconv.Itoa(i))//阻塞time.Sleep(time.Second)} } func main() {//开启协程go test()for i : 1; …

如何配置vite的proxy

1.前言 vite项目&#xff0c;本地开发环境可以通过配置proxy代理实现跨域请求。但是生产环境&#xff0c;该配置不生效&#xff0c;一般使用 nginx 转发&#xff0c;或者后端配置cors 2.解释 server: {port: 9000,proxy: { // 本地开发环境通过代理实现跨域&#xff0c;生产…

基于ssm的轻型卡车零部件销售平台(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的轻型卡车零部件销售平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 轻型卡车零部件销售平台…

C# 批量删除Excel重复项

当从不同来源导入Excel数据时&#xff0c;可能存在重复的记录。为了确保数据的准确性&#xff0c;通常需要删除这些重复的行。 手动查找并删除可能会非常耗费时间&#xff0c;而通过编程脚本则可以实现在短时间内处理大量数据。本文将提供一个使用C# 快速查找并删除Excel重复项…

【ArduinoQuartus】在小脚丫STEP CYC10上安装PulseRain Reindeer并在软核上运行基础功能

【Arduino&Quartus】在小脚丫STEP CYC10上安装PulseRain Reindeer并在软核上运行基础功能 一、将Reindeer软核下载到STEP CYC10&#xff08;一&#xff09;下载PulseRain Reindeer软核&#xff08;二&#xff09;配置Reindeer软核到开发板1.将sof文件转换为jic文件2.将jic文…

Centos7安装单机版Kafka

下载 链接&#xff1a;https://pan.baidu.com/s/1W8lVEF6Y-xlg6zr3l9QAbg?pwdhbkt 提取码&#xff1a;hbkt 上传到服务器/opt目录 安装 # kafka安装目录为 /opt/kafka cd /opt; mkdir kafka; mv kafka_2.13-2.7.0.tgz ./kafka;cd kafka; #解压 tar -zxvf kafka_2.13-2.7.0…

说一说Redis的Bitmaps和HyperLoLog?

本篇内容对应 “Redis高级数据类型”小节 和 “7.5 网站数据统计”小节 对应视频&#xff1a; Redis高级数据结构 网站数据统计 1 什么是UV和DAU&#xff1f; DAUUV英文全称Daily Active UserUnique Visotr中文全称日活跃用户量独立访客如何统计数据通过用户ID排重统计数据通…

上位机图像处理和嵌入式模块部署(qmacvisual图像清晰度)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 做过isp的同学都知道&#xff0c;图像处理里面有一个3A&#xff0c;即自动曝光、自动白平衡和自动对焦。其中自动对焦这个&#xff0c;就需要用输入…

绩效考核存在合理性、公平性、客观性吗?

目录 一、绩效考核流于形式&#xff1a;没有实际考核过 二、考核结果的确定: 主管一人说了算 三、考核结果&#xff1a; 与绩效奖金挂钩吗&#xff1f; 四、考核的滥用&#xff1a;成为公司排挤迫使员工离职的手段 五、公司说&#xff1a; 让你滚蛋&#xff0c;谁还会发你奖…