JVM并发编程AQSsync锁ReentrantLock线程池ThreadLocal

并发编程2

    • synchronized锁实现
    • **AQS**
    • **ReentrantLock实现**
    • **JUC 常用类**
    • 池的概念
  • ThreadLocal
    • ThreadLocal原理
    • 内存泄露
    • 强引用:
    • 软引用
    • 弱引用
    • 虚引用
    • ThreadLocal内存泄露

synchronized锁实现

synchronized是一个关键字,实现同步,还需要我们提供一个同步锁对象,记录锁状态,记录线程信息

控制同步,是依靠底层的指令实现的.

如果是同步方法,在指令中会为方法添加ACC_SYNCHRONIZED标志

如果是同步代码块,在进入到同步代码块时,会执行monitorenter, 离开同步代码块时或者出异常时,执行monitorexit

AQS

AQS(AbstractQueuedSynchronizer 抽象同步队列) 是一个实现线程同步的框架

并发包中很多类的底层都用到了AQS

class AbstractQueuedSynchronizer {private transient volatile Node head;private transient volatile Node tail;private volatile int state; //表示有没有线程访问共享数据  默认是0 表示没有线程访问//修改状态的方法protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}static final class Node {volatile Node prev;volatile Node next;volatile Thread thread;}}

ReentrantLock实现

ReentrantLock完全同过java代码控制

 class ReentrantLock{abstract static class Sync extends AbstractQueuedSynchronizer {abstract void lock();}//非公平锁static final class NonfairSync extends Sync {void lock(){}}//公平锁static final class FairSync extends Sync {void lock(){}}}

在这里插入图片描述

JUC 常用类

在集合类中,像Vector,Hashtable这些类加锁时都是直接把锁加载方法上了,性能就低, 在并发访问量小的情况下,还可以使用, 大并发访问量下,性能就太低了.

ConcurrentHashMap

 HashMap适合单线程场景下的,不允许多个线程同时访问操作,如果有多线程访问会报异常Hashtable 是线程安全的 直接给方法加锁,效率低ConcurrentHashMap 是线程安全的,没有直接给方法加锁, 用哈希表中每一个位置上的第一个元素(第一个是存在元素)作为锁对象哈希表长度是16,那么就有16把锁对象,锁住自己的位置即可,这样如果多个线程如果操作不同的位置,那么相互不影响,只有多个线程操作同一个位置时,才会等待如果位置上没有任何元素,那么采用cas机制插入数据到对应的位置Hashtable ,ConcurrentHashMap  键值都不能为null为什么这样设计,键值都不能为null?map.put("b","b")为了消除歧义  System.out.println(map1.get("a"));//null  值是null  还是键不存在返回null

CopyOnWriteArrayList

ArrayList 是单线程场景下使用的,在多线程场景下会报异常
Vector 是线程安全的,在方法上加了锁,效率低
CopyOnWriteArrayList  写方法操作加了锁(ReentrantLock实现的),
在写入数据时,先把原数组做了备份,把要添加的数据写入到备份数组中,当写入完成后,再把修改的数组赋值到原数组中去
给写加了锁,读没有加锁,读的效率变高了, 这种适合写操作少,读操作多的场景

CopyOnWriteArraySet

CopyOnWriteArraySet 的实现基于 CopyOnWriteArrayList,不能存储重复数据。

辅助类 CountDownLatch

池的概念

字符串常量池

String s1 = “abc”; String s2=“abc”; s1==s2//true

Integer自动装箱 缓存了-128 --+127之间的对象

Integer a = 100; Integer b = 100; a==b //true IntegerCache.cache[i + (-IntegerCache.low)];

数据库连接池

阿里巴巴Druid数据库连接池

帮我们缓存一定数量的链接对象,放在池子里,用完还回到池子中,

减少了对象的频繁创建和销毁的时间开销

线程池

在这里插入图片描述

为减少频繁的创建和销毁线程,

jdk5开始引入了线程池,

建议使用ThreadPoolExecutor类来创建线程池, 这样提高效率.

Java.uitl.concurrent.ThreadPoolExecutor

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

7个参数

corePoolSize: 核心线程池中的数量(初始化的数量) 5

maximumPoolSize:线程池中最大的数量 10 5

keepAliveTime: 空闲线程存活时间 当核心线程池中的线程足以应付任务时, 非核心线程池中的线程在指定空闲时间到期后,会销毁.

unit: 时间单位

workQueue: 5 等待队列, 当核心线程池中的线程都在使用时,如果有任务继续到来,会先将等待的任务放到队列中,如果队列也满了,才会创建新的线程(非核心线程池中的线程)

threadFactory:线程工厂,用来创建线程池中的线程

handler:拒绝处理任务时的策略 4种拒绝策略

线程池工作流程

当有大量的任务到来时,先判断核心线程池中的线程是否都忙着,

​ 有空闲的,直接让核心线程中的线程执行任务

​ 没有空闲的, 判断等待队列是否已满,

​ 如果没满,把任务添加到队列等待

​ 如果已满,判断非核心线程池中的线程是否都忙着

​ 如果有空闲的,没满,交由非核心线程池中的线程执行

​ 如果非核心线程池野已经满了,那么就使用对应的拒绝策略处理.

4种拒绝策略:

AbortPolicy: 抛异常

CallerRunsPolicy: 由提交任务的线程执行 例如在main线程提交,则由main线程执行拒绝的任务 DiscardOldestPolicy: 丢弃等待时间最长的任务

DiscardPolicy: 丢弃最后不能执行的任务

提交任务的方法

void   execute(任务);  提交任务没有返回值Future<?> submit = executor.submit(myTask);//提交任务可以接收返回值
submit.get();  

关闭线程池

shutdown();  执行shutdown()后,不再接收新的任务,会把线程池中还有等待队列中已有的任务执行完,再停止
shutdownNow(); 立即停止,队列中等待的任务就不再执行了.
  如果有空闲的,没满,交由非核心线程池中的线程执行

​ 如果非核心线程池野已经满了,那么就使用对应的拒绝策略处理.

4种拒绝策略:

AbortPolicy: 抛异常

CallerRunsPolicy: 由提交任务的线程执行 例如在main线程提交,则由main线程执行拒绝的任务 DiscardOldestPolicy: 丢弃等待时间最长的任务

DiscardPolicy: 丢弃最后不能执行的任务

提交任务的方法

void   execute(任务);  提交任务没有返回值Future<?> submit = executor.submit(myTask);//提交任务可以接收返回值
submit.get();  

关闭线程池

shutdown();  执行shutdown()后,不再接收新的任务,会把线程池中还有等待队列中已有的任务执行完,再停止
shutdownNow(); 立即停止,队列中等待的任务就不再执行了.

ThreadLocal

ThreadLocal中填充的变量属于当前线程,改变量对其他线程而言是隔离的
ThreadLocak为变量在每个线程创建了一个副本,每个线程可以访问自己内部的副本变量

static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
@Overrideprotected Integer initialValue() {return 1;}
};

ThreadLocal原理

首 先 ThreadLocal 是 一 个 泛 型 类 , 保 证 可 以 接 受 任 何 类 型 的 对 象 ,ThreadLocal 内 部 维 护 了 一 个 Map , ThreadLocal 实 现 了 一 个 叫做 ThreadLocalMap 的静态内部类。
而我们使用的 get()、set() 方法其实都是由这个 ThreadLocalMap 类对应的 get()、set() 方法实现的。首 先 ThreadLocal 是 一 个 泛 型 类 , 保 证 可 以 接 受 任 何 类 型 的 对 象 。

在这里插入图片描述
在这里插入图片描述
最终变量是放在当前线程的ThreadLocalMap中,并不是存在ThreadLocal上,ThreadLocal主要作为key,用于存读操作

内存泄露

当对象已经不再被引用,但是垃圾回收机制无法回收该对象,就会产生内存泄露问题(例如数据库链接对象,流对象,socker)

强引用:

当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收。

强引用是我们最常见的普遍对象引用,只要还有强引用指向一个对象,就能表明对象还活着,垃圾收集器不会碰这种对象。在JAVA最常见的就是强引用,把一个对象赋给一个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收,因此强引用时造成Java内存泄漏的主要原因之一。

对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用复制为null,一版认为就是可以背垃圾收集了。

public class StrongReferenceDemo {public static void main(String []args) {Object obj1 = new Object(); //这样定义默认是强引用Object obj2 = obj1;obj1 = null;System.gc();System.out.println(obj1);System.out.println(obj2);}
}

对象如果有强引用关系,必定不会被回收

软引用

软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾收集,对于只有软引用的对象来说,

当系统内存充足时它不会被回收,当系统内存不足时它会被回收。

软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收!

public class SoftReferenceDemo {public static void main(String []args) {Object o1 = new Object();SoftReference<Object> softReference = new SoftReference<Object>(o1);System.out.println(o1);System.out.println(softReference.get());o1 = null;System.gc();try {byte[] bytes = new byte[30*1024*1024];} finally {System.out.println(o1);System.out.println(softReference.get());}}
}

弱引用

弱引用需要用java.lang.ref.WeakReference类来实现,它比软引用的生存区更短。

对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。

public class WeakReferenceDemo {public static void main(String[] args) {Object o1 = new Object();WeakReference<Object> weakReference = new WeakReference<Object>(o1);System.out.println(o1);System.out.println(weakReference.get());o1 = null;System.gc();System.out.println("----------------------------");System.out.println(o1);System.out.println(weakReference.get());}
}

虚引用

虚引用需要java.lang.ref.PhantomReference类来实现。

顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时间都可能被垃圾回收

器回收,它不能单点使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。

虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomReference的get方法总是返回null,因此无法访问对应的引用对象,其意义在于说明一个对象已经进入了finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作。

换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用fianlize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作

public class PhantomReferenceDemo {public static void main(String []args) throws Exception {Object o1 = new Object();ReferenceQueue<Override> referenceQueue = new ReferenceQueue<>();PhantomReference<Object> phantomReference = new PhantomReference(o1,referenceQueue);System.out.println(o1);System.out.println(phantomReference.get());System.out.println(referenceQueue.poll());System.out.println("-----------------");o1 = null;System.gc();Thread.sleep(500);System.out.println(o1);System.out.println(phantomReference.get());System.out.println(referenceQueue.poll());}
}

ThreadLocal内存泄露

在这里插入图片描述
TreadLocalMap 使用 ThreadLocal 的弱引用作为 key,如果一个 ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被 GC 回收,这样就会导致ThreadLocalMap 中 key 为 null, 而 value 还存在着强引用,只有 thead 线程退出以后,value 的强引用链条才会断掉。
但如果当前线程再迟迟不结束的话,这些 key 为 null 的 Entry 的 value 就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value

永远无法回收,造成内存泄漏。
ThreadLocal 正确的使用方法
每次使用完 ThreadLocal 都调用它的 remove()方法清除数据。

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

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

相关文章

【JavaEE】网络原理之初识

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

操作系统-八股

进程基础&#xff1a; 进程定义&#xff1a;运行中的程序&#xff0c;有独立的内存空间和地址&#xff0c;是系统进行资源调度和分配的基本单位。 并发&#xff0c;并行 并发就是单核上面轮询&#xff0c;并行就是同时执行&#xff08;多核&#xff09;&#xff1b; 进程上下…

ffmpeg面试题整理

1. 基础概念 问题&#xff1a;FFmpeg 是什么&#xff1f;它的核心功能有哪些&#xff1f; 编解码&#xff1a;支持几乎所有音视频格式&#xff08;如 H.264, AAC, MP3&#xff09;。转换&#xff1a;在不同容器格式之间转换&#xff08;如 MP4 → MKV&#xff09;。流处理&…

chrome浏览器插件拓展捕获页面的响应体内容

因为chrome extension官方没有的直接获取响应体的方法&#xff0c;所以需要自己实现方法来获取&#xff0c;实现的方式有很多种&#xff0c;这是记录的第二种&#xff0c;第一种就是使用vconsole来实现&#xff0c;vconsole是一个开源框架&#xff0c;一个轻量、可拓展、针对手…

探索天然分子swertiamarin调控脂肪生成的新机制

随着生活方式的改变和环境的恶化&#xff0c;糖尿病这一全球性健康挑战日益严峻。据世界卫生组织统计&#xff0c;全球糖尿病患者数量不断攀升&#xff0c;其中2型糖尿病&#xff08;T2DM&#xff09;占据了绝大多数。T2DM不仅影响患者的生活质量&#xff0c;还给医疗系统带来了…

沐数科技数据开发岗笔试题2025

描述性统计 标准差 答案: A 解析: 标准差 衡量数据集中数值变化或离散程度的一种度量。它反映了数据集中的各个数值与数据集的平均值&#xff08;均值&#xff09;之间的偏离程度。标准差越大&#xff0c;表明数据的分布越分散&#xff1b;标准差越小&#xff0c;表明数据…

Java 集合遍历过程中修改数据触发 Fail-Fast 机制 ,导致报ConcurrentModificationException异常

Java Fail-Fast 机制 Fail-Fast 机制是 Java 集合框架中的一种错误检测机制&#xff0c;用于在遍历集合时检测结构修改。如果在迭代器创建之后&#xff0c;集合被修改&#xff08;例如添加或删除元素&#xff09;&#xff0c;并且这种修改不是通过迭代器自身的 remove() 方法进…

Qt-ZMQ的使用补充(pub-sub)

之前写过一篇Qt使用ZMQ的博客Qt网络编程-ZMQ的使用&#xff0c;本文是其的补充部分。 Linux上编译使用 首先这次实在Linux上进行演示&#xff0c;下载zmq源码&#xff0c;安装cmake&#xff0c;使用cmake进行编译。下载之后解压&#xff1a; 输入命令&#xff1a; cd ..mkdi…

C++的名称空间

C++的名称空间(namespace)是一种用于组织代码、防止命名冲突的机制。以下是名称空间的详细说明和使用建议: 1. 名称空间的定义 使用namespace关键字定义,内部可包含变量、函数、类等: namespace MyNamespace {int a;void func() {} }2. 访问方式 作用域解析运算符:::显…

记录致远OA服务器硬盘升级过程

前言 日常使用中OA系统突然卡死&#xff0c;刷新访问进不去系统&#xff0c;ping服务器地址正常&#xff0c;立马登录服务器检查&#xff0c;一看磁盘爆了。 我大脑直接萎缩了&#xff0c;谁家OA系统配400G的空间啊&#xff0c;过我手的服务器没有50也是30台&#xff0c;还是…

[测试]自动化的概念 及使用Selenium实现Web自动化测试

文章目录 1. 自动化1.1 自动化概念1.2 自动化分类1.2.1 接口自动化1.2.2 UI自动化 1.3 自动化测试金字塔 2. Web自动化测试2.1 驱动 3. Selenium3.1 一个简单的Web自动化示例3.2 Selenium 驱动 浏览器的工作原理 1. 自动化 1.1 自动化概念 自动化是指自动地代替人的行为完成…

Python教程(三):类对象、闭包、装饰器、类型注解、MRO

Python总结&#xff08;三&#xff09; 本系列其他教程&#xff1a; Python教程(一)&#xff1a;基本语法、流程控制、数据容器 Python教程(二)&#xff1a;函数、异常、模块&包、文件读取、常用模块 文章目录 Python总结&#xff08;三&#xff09;一、类&对象1.1 成…

什么是 HTML?

HTML 是用来描述网页的一种语言。 HTML 指的是超文本标记语言: HyperText Markup LanguageHTML 不是一种编程语言&#xff0c;而是一种标记语言标记语言是一套标记标签 (markup tag)HTML 使用标记标签来描述网页HTML 文档包含了HTML 标签及文本内容HTML文档也叫做 web 页面 HT…

【Hadoop】Hadoop的简要介绍

Hadoop是一个由Apache基金会所开发的分布式系统基础架构&#xff0c;主要用于解决海量数据的存储及分析计算问题。以下是对Hadoop的详细介绍&#xff1a; 目录 一、Hadoop的起源与发展 二、Hadoop的核心组件 1.HDFS&#xff1a; 2.MapReduce&#xff1a; 3.YARN&#xff…

如何用AI制作PPT,轻松实现高效演示

如何用AI制作PPT&#xff0c;轻松实现高效演示&#xff01;在今天这个快节奏的时代&#xff0c;我们的工作方式越来越依赖智能工具。而当涉及到演示文稿时&#xff0c;传统的PPT制作方式往往繁琐且耗时。很多人一提到制作PPT就头大&#xff0c;特别是在内容需要多次修改、调整布…

Canoe Panel基础功能介绍

文章目录 一、新建 Panel 面板二、添加 Panel 面板三、删除 Panel 面板四、Panel视图&#xff08;views&#xff09;五、控件布局1. 对齐布局2. 控件大小布局 六、Panel 属性设置1. 设置背景色和背景图片2. 调整 Panel 画布大小 提示&#xff1a;如何使用 Panel 面板参考 CANoe…

超声重建,3D重建 超声三维重建,三维可视化平台 UR 3D Reconstruction

1. 超声波3D重建技术的实现方法与算法 技术概述 3D超声重建是一种基于2D超声图像生成3D体积数据的技术&#xff0c;广泛应用于医学影像领域。通过重建和可视化三维结构&#xff0c;3D超声能够显著提高诊断精度和效率&#xff0c;同时减少医生的脑力负担。本技术文档将详细阐述…

2.2 企业级ESLint/Prettier规则定制

文章目录 1. 为什么需要企业级代码规范2. 工具选型对比3. 完整配置流程3.1 项目初始化3.2 ESLint深度配置3.3 Prettier精细配置3.4 解决规则冲突4. 高级定制方案4.1 自定义ESLint规则4.2 扩展Prettier插件5. 团队协作策略5.1 配置共享方案5.2 版本控制策略6. CI/CD集成7. 常见问…

QT创建项目(项目模板、构建系统、选择类、构建套件)

1. 项目模版 项目类型界面技术适用场景核心依赖模块开发语言Qt Widget ApplicationC Widgets传统桌面应用&#xff08;复杂控件&#xff09;Qt WidgetsCQt Console Application无 GUI命令行工具、服务Qt CoreCQt Quick ApplicationQML/Quick现代跨平台应用&#xff08;动画/触…

oracle11.2.0.4 RAC 保姆级静默安装(二) DB数据库软件

1.响应文件配置 [rootdb11g1 software]# su - oracle [oracledb11g1 ~]$ cd /software/database/ [oracledb11g1 database]$ cd response/ [oracledb11g1 response]$ vi db_install.rsp oracle.install.optionINSTALL_DB_SWONLY ORACLE_HOSTNAMEdb11g1 UNIX_GROUP_NAME…