一.线程复习

1.什么是线程,进程

进程是操作系统分配资源的基本单位

线程是进程中的一个执行单元(一个独立执行的任务),是cpu执行的最小单元

2.Java中如何创建线程

1.继承Thread类,重写run(),直接创建子类的对象

2.类实现Runnable接口,重写run(),  任务类   new Thread(任务类对象)

3.类实现Callable接口

4.线程池

3.线程中常用的方法

run()   call()

Thread类中的方法:

        start();启动线程的,把线程注册到操作系统private native void start0();

        sleep();让线程休眠指定的时间

        join();让其他线程等待当前线程执行完成后再执行

        yeild();线程礼让

        setDaemon();设置线程为守护线程

        currentThread();获得当前正在执行的线程

        wait();让线程等待,只能被其他线程唤醒

        notify();notifyAll();唤醒被wait等待的线程

4.线程的状态

5.多线程

(1)什么是多线程

在程序中(进程)可以创建多个线程来分别执行不同的任务

(2)多线程优缺点

优点:可以提高程序执行效率

缺点:线程多了,需要操作系统进行管理的,占用开销的(不是啥事情都创建线程执行的.)

           多个线程同时访问共享资源(数据)会出现问题

(3)线程同步

加锁排队 (饭堂买饭 排队+加锁 一次只能有一个买饭)

synchronized关键字:

   synchronized修饰方法 非静态方法锁对象是this 静态方法是类的Class对象

   synchronized修饰代码块

ReentrantLock

public class ReentrantLockDemo  implements  Runnable{int num = 10;/*ReentrantLock是java.util.concurrent.locks包下的类,是java代码实现的一种锁控制只能手动的加锁和手动的释放锁只能对某段代码块加锁,不能给整个方法加法*/ReentrantLock reentrantLock = new ReentrantLock();@Overridepublic void run() {while (true){try { reentrantLock.lock();//加锁   if (num > 0) {System.out.println(Thread.currentThread().getName() + "买到第" + num + "张票");num--;} else {break;}}finally {reentrantLock.unlock();//释放锁}}}
}
(4)死锁

多个线程相互持有对方需要的锁对象不释放,二形成的一种相互等待获取锁的现象,

死锁发生后,程序不会报错,只能相互等待,不继续向后执行了.

如何避免死锁发生:

        避免锁的嵌套使用

        避免多个同步代码块中的锁相互使用

口语描述死锁:

       线上1和线程2 同时访问两个代码块, 线程1访问的同步代码块使用A锁,在A锁的同步代码块又使

用了B锁.  

        线程2在访问的同步代码块中使用B锁,在B锁的同步代码块中又用到了A锁,有可能形成死锁.

(5)线程通信(生产者,消费者模型)

在线程同步的基础上进行的,两个线程相互牵制执行

wait(); 线程等待

notify(); 唤醒等待的线程

只能在同步代码块(同步方法)中使用, 还只能通过同步锁对象调用

案例:交替打印数字

public class PrintNum  implements  Runnable{int num = 0;Object obj = new Object();@Overridepublic void run() {while (true){synchronized(obj){obj.notify();System.out.println(Thread.currentThread().getName()+":"+num++);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}try {obj.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

wait()和sleep()区别:

        所属的类不同: wait()属于Object类 sleep()属于Thread类

        阻塞后唤醒方式不同: wait()让线程等待后,需要让另一个线程通过notify()唤醒,如果不唤醒一直

等待

                                           sleep()休眠执定的时间,时间到了后,自动唤醒

        释放锁不同: sleep()不会释放锁

                            wait()会释放锁

二.线程进阶---并发编程

后面谈论的线程内容,几乎都是在多线程对同一共享数据操作的基础上进行.

1.多线程优缺点

优点: 可以提高程序执行效率

缺点: 线程多了,需要操作系统进行管理的,占用开销的(不是啥事情都创建线程执行的.)

         多个线程同时访问共享资源(数据)会出现问题

并发(高并发): 计算机领域指的是同一时刻只能有一个任务执行,多个任务依次执行

                       汉语并发指的是同时执行

并发执行: 在很多用户同时访问时,应当让多个用户并发执行(一个时间段内依次执行)

并行执行: 在同一个时间点上,多个任务同时执行

2.并发编程核心问题

        多个线程同时对同一个资源访问的情况下. 为什么会出现问题.

(1)不可见性

        首先了解java程序运行的内存模型(JMM)

        java在线程操作时,先把主内存中的数据加载到线程的工作内存中,然后对数据进行操作, 但是

线程A在自己的工作内存中操作玩出,线程B不知道,做了同样的操作,最终结果和预期结果不一样

(2)乱序性(无序性)重排序

系统为了优化,在执行某些指令时,会将一些看起来没关系的指令执行顺序改变,但是在,某些情况下会

产生问题.

1    int a = 10;

2    int  b =  从数据库读取

3    int c = a+b;

(3)非原子性

i++;在多线程情况下时线程安全的吗?

i++高级语言,在底层执行时,会被分为3条件

加载i

i+1

i=2

线程的切换执行会带来原子性问题

java内存模型为每个线程提供工作内存(缓存),导致不可见性问题

系统指令优化会把一些指令顺序重排序(在执行一些较为耗时的指令时,把一些其他指令先行执行),

可能导致程序无法正常执行

线程切换执行会打破指令执行的原子性 ,例如++操作 分为三条指令, 但是在执行这3条指令时,cpu可

能在执行时,切换到其他线程执行,打破原子性执行.

(4)如何解决以上3个问题:

volatile

volatile关键可以解决不可见性和乱序性

**volatile**修饰的共享变量,在被一个线程操作后,可以做到立即对其他线程可见 (volatile底层

实现内存屏障)

volatile修饰的变量禁止对其的执行顺序重排序

volatile只能解决不可见性和重排序问题, 不能解决非原子性问题

(5)如何解决非原子性问题:

        1.加锁(ReentrantLock和synchronized)

        2.使用原子类来解决++在多线程中非原子性问题

AtomicInteger 是一个原子类,能够在不加锁的情况下,实现多线程++操作不出问题,结果正确

private  static AtomicInteger atomicInteger = new AtomicInteger(0);atomicInteger.incrementAndGet();  自增并获得

CAS 机制

CAS(Compare-And-Swap) :比较并交换

特点: 不加锁实现对变量++操作保证原子性.

优点: 线程不会进入到阻塞状态,一直自旋,效率高

缺点: 线程一直自旋,对cpu开销大, 所以原子类适用于线程少的情况

3.Java中的锁分类

(1)乐观锁/悲观锁

乐观锁: 就是没有加锁的实现. AtomicInteger中的实现就是不加锁的,通过自旋比较实现(CAS)

悲观锁: 就是加锁的实现,认为不加锁是会出问题的 ,ReentrantLock和synchronized都是悲观锁

(2)可重入锁

ReentrantLock和synchronized都是可重入锁

可重入锁又名递归锁, 指的是一个线程在外层方法获得锁时,可以直接进入到内层的加锁的方法中.

(3)自旋锁

指的是对synchronized获得锁的一种描述(特点), 线程在获得锁时,是自旋的不断尝试去获得锁

(4)公平锁/非公平锁

公平锁: 就是排队获得锁,有先来后到 ReentrantLock 既可以是公平锁也可以是非公平锁

非公平锁: 就是抢锁,谁抢到谁执行, 有可能后来的线程先抢到锁 synchronized ReentrantLock

(5)读写锁

ReentrantReadWriteLock

特点: 读读不互斥, 读写互斥, 写写互斥

适合读(查询)多,写少的场景, 提高读的效率

(6)共享锁和独占锁

独占锁: synchronized ReentrantLock都是独占锁,就是有我没他,一次只能有一个线程执行.

共享锁: 一个锁可以被多个线程持有, 读写锁中的读锁就是共享锁

4.synchronized锁的实现

jdk1.7之后,对synchronized锁进行了优化(jdk7之前synchronized锁没有状态,都是自旋的获取锁),

jdk7之后为synchronized锁设计了不同的状态.

无锁状态: 没有线程进入到同步代码块就是无锁状态

偏向锁状态: 只有一个线程访问同步代码块时,同步锁中记录线程id,下次线程访问时,可以快速的获

得锁.

轻量级锁状态: 当线程数量大于1个之后,锁状态由偏向锁升级为轻量级锁, 线程不会阻塞,以自旋方

式获得锁,提高获取锁的效率.

重量级锁状态: 当锁状态为轻量锁时,如果线程自旋到一定次数还获取不到锁,那么锁会升级为重量级

锁,让获取不到锁的线程进入到阻塞状态,等待操作系统调度.

使用synchronized锁的时候,必须为锁提供一个同步锁对象的,此对象就是用来记录锁状态的

对象中有一个区域叫对象头,对象头中中有一块区域叫mark word,记录对象运行时的一些数据,

如锁状态,哈希值,GC分代年龄,当前线程id.

synchronized时java中内置的一种的锁,底层实现是靠底层指令进行控制的,

使用时必须提供一个同步锁对象,用来记录锁的各种状态.

5.AQS

AbstractQueuedSynchronizer 抽象同步队列, 并发包下面很多类的底层实现都会用到

内部有一个int类的变量state,用来记录有没有线程使用

内部会构建一个队列,用来存储没有获得锁的线程

6.ReentrantLock锁实现

ReentrantLock 基于 AQS的,

ReentrantLock 可以实现公平锁和非公平锁

内部结构

公平和非公平的区别

三.Java集合类复习

javaSE中3个重点: 面向对象相关知识

                              集合类 (数据结构,线程)

                              多线程

次重点: 网络 (计网)

             IO

             常用类

             异常

单列集合 Collection

       List

                ArrayList 底层数组实现 查询块

                LinkedList   底层链表   查询慢

                Vector 底层也是数组,是线程安全的

        Set

                HashSet

                TreeSet

双列集合 Map

        HashMap

        TreeMap

        Hashtable

1.你能讲一下HashMap吗?

基本特点: 双列集合,键不能重复,值可以重复,可以有一个key为null

数据结构:

源码

put方法源码分析

public V put(K key, V value) {//通过key计算哈希值return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {int h;                       为了减少哈希值冲突return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; //哈希表Node<K,V> p; //记录之前int n, i; //n是哈希表长度, i是索引if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;//创建哈希表if ((p = tab[i = (n - 1) & hash]) == null) // == 97%16 根据哈希值计算位置//如果该位置为null,则直接将key,value包装到一个node对象中,直接存放到第i个位的第一个tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;//判断key是否重复, 先判断哈希值(快),但是哈希有问题,值相同,但内容不同,//所以在哈希值相同时,需要调用equals(),判断内容是否相同.if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;//当key不重复时,判断类型是树类型还是链表类型else if (p instanceof TreeNode)//已经是树类型,向红黑树上添加元素e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {//链表for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);//添加完成后,判断链表长度if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);//转红黑树break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;//key相同时,会用后面key的值,覆盖之前的相同的key的值afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}

重点参数:

1.哈希表长度: 默认是16

2.哈希表每次扩容原来 2 倍

3.哈希表的负载因子 0.75, 哈希表不会装满的,装满会影响查询效率,所以会牺牲一定的空间而换取查询效率

4.链表长度上限是 8 ,尝试将链表转为红黑树,但是不一定转成功, 还会判断哈希表长度,哈希表长度小于64 会先扩容哈希表,扩容后所有元素位置需要重新计算,这样链表会变短, 只有当链表长度大于等于8且哈希表长度大于64,链表才会转成红黑树.

5.当红黑树节点数量减少为6个时,红黑树退化成链表

2.ConcurrentHashMap

ConcurrentHashMap是一个线程安全的map,加锁的方式与Hashtable不同

Hashtable直接在方法上加锁,一次只能有一个线程进入方法操作.

ConcurrentHashMap不是给方法加的锁,个每个哈希表中的位置加锁

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

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

相关文章

小车循迹功能的实现(第六天)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-削好皮的Pineapple! &#x1f468;‍&#x1f4bb; hello 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 削好皮的Pineapple! 原创 &#x1f468;‍&#x1f4…

C++ auto与 for循环

一、数组 #include <iostream> #include <vector> using namespace std; int main() {int vec[6] {1,2,3};for (auto num : vec) { /* num 是 int */ cout << "Hello, world!" << num <<endl;}return 0; }二、STL容器与迭代器 for 循…

【RK3568+PG2L50H开发板实验例程】FPGA部分 | ROM、RAM、FIFO 的使用

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 1.实验简介 实验目的&#xff1a; 掌握紫光平台的 RAM、ROM、FIFO IP 的使用 实验环境&#xff1a; Window11 PDS2022…

力扣-21.合并两个有序链表

题目链接 21.合并两个有序链表 class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode p1 list1;ListNode p2 list2;ListNode p new ListNode(0);ListNode cur p;while (p1 ! null && p2 ! null) {if (p1.val > p2.val) …

MoE混合专家模型:千亿参数的高效推理引擎与架构革命

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 从稀疏激活到多模态协同的智能计算范式 &#x1f9e9; 一、核心思想与…

【论文笔记】BlockGaussian:巧妙解决大规模场景重建中的伪影问题

论文地址&#xff1a;https://arxiv.org/pdf/2504.09048 大规模场景的重建方法不仅仅对于高空航拍数据有效&#xff0c;而且对于地面大中场景也有增强效果&#xff0c;故专门来学习一下这一方向的知识。感谢作者大佬们的great work。 Abstract 三维高斯泼溅&#xff08;3DGS…

网络众筹项目数据库(2014-2024.11)

1727网络众筹项目数据库&#xff08;2014-2024.11&#xff09;数据简介作为新兴互联网融资模式&#xff0c;众筹已成为越来越多创业者和中小企业获取资金的渠道&#xff0c;但众筹项目一直面临融资成功率低的困难&#xff0c;成功融资的项目在许多平台上占比不足五成。而目前对…

k8s新增jupyter服务

k8s新增服务 常用命令 kubectl apply -f xxxxxx.yaml # 部署资源&#xff0c;顺序&#xff1a;namespace -> pvc -> deployment -> servicekubectl create namespace jupyter # 创建namespacekubectl get namespaces # 查看nskubectl get pods -n jupyter # 查看p…

结构化数据、非结构化数据区别

一、核心定义结构化数据&#xff1a;指具有固定格式、可直接用二维表&#xff08;如数据库表&#xff09;表示的数据&#xff0c;其字段&#xff08;列&#xff09;定义明确&#xff0c;数据之间的关系清晰。例如&#xff1a;Excel 表格中的数据、关系型数据库&#xff08;MySQ…

Linux修炼:基础指令

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》、《Linux修炼&#xff1a;终端…

【Linux网络】深入理解HTTP/HTTPS协议:原理、实现与加密机制全面解析

协议是通信双方必须遵守的规则&#xff0c;确保数据能够正确传输和解析&#xff0c;它规定了数据格式、传输顺序、错误处理等细节。应用层的协议一般都是我们自己进行定义的&#xff0c;但是有很多程序员前辈已经写出来了很哇塞的协议&#xff0c;我们直接进行学习和使用即可HT…

浅尝 Spring AI【使用超级简单~】

一直想要体验下 Spring AI&#xff0c;最近自己的一个工具有这个需求&#xff0c;所以这里准备使用下。其实使用起来超级简单。 1.IDEA 新建 Spring项目 1&#xff09;这里可以根据自己的喜好选择 项目名、jdk版本等 2&#xff09;这里选择 在ai中选择 openAI 即可。然后我另…

DDL期间TDSQL异常会话查询造成数据库主备切换

问题描述&#xff1a;7*24联机交易系统&#xff0c;傍晚时分&#xff0c;从客户端后台对3千万行的大表执行缩短varchar类型字段长度的ddl语句&#xff0c;执行期间&#xff0c;为了查看ddl进度&#xff0c;从TDSQL-MySQL赤兔前端页面点击异常会话查询&#xff0c;之后数据库卡住…

弧焊机器人气体全方位节能指南

氩弧焊&#xff08;TIG焊接&#xff09;作为其中一种高效且精密的技术&#xff0c;凭借其稳定性和高质量的焊接效果&#xff0c;在航空航天、汽车制造、船舶建造以及石油化工等领域占据了不可或缺的地位。氩弧焊通过使用惰性气体&#xff08;如氩气&#xff09;保护电弧和熔池&…

数据清洗(ETL/ELT)原理与工具选择指南:企业数字化转型的核心引擎​

目录 一、数据清洗&#xff08;ETL/ELT&#xff09;到底在干啥&#xff1f; 1.揪出并处理异常值 2.把缺失的数据补上&#xff08;或处理好&#xff09; 3.数据转换与标准化 4.一致性校验 二、工具怎么选&#xff1f;看菜吃饭&#xff0c;量体裁衣 1.数据量不大、要求不高…

阿里云服务器,CentOS7.9上安装YApi 接口管理平台

目录 1.node安装 1.1下载node,解压 1.2 部署bin文件 1.3 安装mongodb 2.启动yapi 2.1 前置命令 2.2 启动服务 3.利用pm2方便服务管理维护 3.1.安装pm2 3.2 常用 PM2 命令 4.常见问题 4.1. 确认 MongoDB 是否安装 4.2. 安装 MongoDB&#xff08;若未安装&#xff…

阿里云错题集分享

有最近想要考试阿里云的可以私信我 &#xff0c;一起加油错题集1.在使用阿里云的负载均衡SLB实例时&#xff0c;做了如下健康检查的配置:成功响应和超时响应时间均为1秒&#xff0c;健康检查间隔为2秒&#xff0c;不健康阈值为3&#xff0c;健康阈值为3。即对于确认一个云服务器…

Android 12 - 部分相机横屏显示方案

1.相机过渡界面方向旋转 Android 10 - 相机过渡界面默认角度 同A10 有些区别&#xff0c;再次增加记录修改。 这个文件没有修改&#xff0c;只是说明 src/com/android/camera/CameraActivity.javaprivate void freezeScreenCommon(boolean async) {long startTime System.…

Operation Blackout 2025 Phantom Check hayabusa+ControlSet001+VirtualBox

QAQA攻击者使用哪个 WMI 类来检索型号和制造商信息以进行虚拟化检测&#xff1f;Win32_ComputerSystem攻击者执行了哪个 WMI 查询来检索计算机的当前温度值&#xff1f;SELECT CurrentTemperature FROM MSAcpi_ThermalZoneTemperature攻击者加载了 PowerShell 脚本以检测虚拟化…

《O-PAS™标准的安全方法》白皮书:为工业自动化系统筑起安全防线

The Open Group 最新白皮书《O-PAS™标准的安全方法》重磅发布&#xff0c;为流程工业在迈向开放架构与多供应商互操作的过程中&#xff0c;指明了安全实践的方向。O-PAS™标准的安全方法ABOUT PUBLICATION亮点一&#xff1a;首次系统阐释 O-PAS™ 标准安全方法与 IEC/ISA 6244…