栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程相关知识

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程相关知识

创建多少个线程合适

如何计算wait/compute,线下分析可以用profiler,线上用arthas,分布式系统可以使用链路追踪 

线程创建原则

一个不要:不要在构造方法启动线程(指令重排,this 溢出)

synchronized关键字保证可见性和原子性,不保证有序性

race condition => 竞争条件 , 指的是多个线程访问共享数据的时候产生竞争

数据的不一致(unconsistency),并发访问之下产生的不期望出现的结果

如何保障数据一致呢?--> 线程同步(线程执行的顺序安排好),

monitor (管程) ---> 锁

critical section -> 临界区

如果临界区执行时间长,语句多,叫做 锁的粒度比较粗,反之,就是锁的粒度比较细

具体: 保障操作的原子性(Atomicity)

    悲观的认为这个操作会被别的线程打断(悲观锁)synchronized(上一个小程序)

    乐观的认为这个做不会被别的线程打断(乐观锁 自旋锁 无锁)cas操作CAS = Compare And Set/Swap/Exchange

synchronized的底层原理

字节码层面:monitorEnter ,monitorExit

synchronized锁升级

synchronized锁有四种状态,无锁,偏向锁,轻量级锁,重量级锁,这几个状态会随着竞争状态逐渐升级,锁可以升级但不能降级,但是偏向锁状态可以被重置为无锁状态

偏向锁
为什么要引入偏向锁?

因为经过HotSpot的作者大量的研究发现,大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁。

偏向锁原理和升级过程

当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后线程1再次获取锁的时候,需要比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获取锁对象),则无需使用CAS来加锁、解锁;如果不一致(其他线程,如线程2要竞争锁对象,而偏向锁不会主动释放因此还是存储的线程1的threadID),那么需要查看Java对象头中记录的线程1是否存活,如果没有存活,那么锁对象被重置为无锁状态,其它线程(线程2)可以竞争将其设置为偏向锁;如果存活,那么立刻查找该线程(线程1)的栈帧信息,如果还是需要继续持有这个锁对象,那么暂停当前线程1,撤销偏向锁,升级为轻量级锁,如果线程1 不再使用该锁对象,那么将锁对象状态设为无锁状态,重新偏向新的线程。

轻量级锁
为什么要引入轻量级锁?

轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放。

轻量级锁原理和升级过程

线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(称为DisplacedMarkWord),然后使用CAS把对象头中的内容替换为线程1存储的锁记录(DisplacedMarkWord)的地址;

如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。 自旋锁简单来说就是让线程2在循环中不断CAS

何时升级为重量级锁?

但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,有线程自旋超过十次,或着自旋的线程数超过cpu核数的一半.jdk6以后,加入自适应自旋,adapative self spinning ,由jvm自己控制何时升级为重量级锁> 那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。


为什么有自旋锁还用重量级锁

 偏向锁一定比自旋锁效率高?  为什么synchronized必须是可重入锁

同一个线程锁方法1调用锁方法2,再调用2的时候也要获取锁(同一把锁,同一个锁对象),如果此时不能可重入就不能调用了

 

如何控制线程执行顺序

  Thread中,join()方法 - knightsoul - 博客园

常见多线程面试题之Thread的join()方法_2的32次方-CSDN博客_thread.join

Reentrant和synchronized的区别

使用注意 try finally

底层是 cas

百度安全验证

ReadWrite的使用场景

一道面试题比较synchronized和读写锁 - V青山绿水 - 博客园

例如黑白名单筛选   (读取大量的号码,检查是否是黑名单号码,如果是,开始写操作())

线程间的通信问题   控制线程的交替执行

 几种方法

1.Collections.synchrnized()

2.两次 wait notify

3.两次countdownlatch 

4.两次LockSupport park unpark

5.Semaphore 加join

顺序交替打印问题

编写一个程序,创建两个线程,要求分别输出26个字母,在输出结果时,要显示哪个线程输出的字母。? - 知乎

经典面试题:两个线程交替打印数字和字符 - 灰信网(软件开发博客聚合)

生产者和消费者问题

一篇文章,让你彻底弄懂生产者--消费者问题 - 简书

ThreadLocal原理

声明一个threadlocal变量的时候,先看他的set方法

set方法的实质是将传入的值存入一个map中,而这个map是属于当前线程的

 也就是说其他的线程获取不到, 当调用get方法的时候,只能获取到的是本线程里面的值

threadlocal与弱引用  如何避免内存泄漏

强软弱虚引用的特点 ,一般用在什么地方

softRefenerce  一般用做缓存 ,内存不足就清理掉

weakRefenerce    一个典型应用就是应用在threadlocal

phantomRefenerce  特点: 获取不到值,被gc的对象存到一个map集合中,可用于操作直接内存

线程池相关

如何正确的创建线程池

线程池的几个参数

如何自定义线程名称

如何自定义拒绝策略

为什么不建议用Executors

常用的workQueue有哪些?

线程池的工作队列 - guoyu1 - 博客园

forkjoinpool相关

关键类,实现方法  逻辑 任务拆分,可以指定拆分逻辑,pool执行

介绍 ForkJoinPool 的适用场景,实现原理_大大肉包博客-CSDN博客_forkjoinpool

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/760297.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号