多线程基本概念
- 什么是进程,线程?
线程是进程的最小执行单元,相当于不同的执行路径
- run和start的区别?
run只是单纯的方法调用,在主线程进行.start相当于开启一个线程
- 线程的启动的三种方式
Thread,runable,线程池
-
线程的6个状态
-
可重入锁和不可重入的区别
可重入锁也叫递归锁,是在一个线程获取锁后,内部如果还需要获取锁,可以直接获取的锁(前提锁对象得是同一个对象或者class)。
不可重入锁也就是相反,线程获取锁后,内部不能再获取锁,由于之前已经获取过还没释放而阻塞,会导致线程死锁。
所以可重入锁的一个优点是可一定程度避免死锁。
可重入锁有ReentrantLock和synchronized。
非可重入锁有NonReentrantLock
- 出现异常,锁会释放吗?
会
- 锁升级的过程?
第一次:markword 记录这个线程id(偏向锁)
如果线程争用:升级为自旋锁
10次以后,升级为重量级锁 - OS
锁只能升级,不能降级
- 什么时候用自旋锁,什么时候用系统锁?
自旋锁占cpu,但不访问操作系统,在用户态解决锁的问题,不经过内核态.
加锁代码执行时间短,且线程数少用自旋锁.执行时间长或线程数多用系统锁.不然cpu受不了
- synchronized可以锁定String常量,Integer,Long吗?
不能,会存在问题 synchronized ("A".intern()),
串池大小依赖服务器内存,且只有等待fullGC,极端情况下会导致频繁fullGC。并且在数据量很大的情况下,将字符串放入常量是存在性能问题。
- volitile的两个作用?
1.保持可见性(缓存一致性协议)
2.禁止指令重排序
public class Instance {
private static volatile Instance instance;
static Instance getInstance(){
if(instance == null){
synchronized (Instance.class){
if(instance == null){
return new Instance();
}
}
}
return instance;
}
}
- 为什么volatile不能保证多个线程共同修改某个变量带来的不一致问题
线程1改了值,线程 2,3同时读到了这个值,count++不具备原子性
-
用于加锁的对象要记得加final,防止被修改
-
什么是CAS?
无锁优化,自旋.Compare And Set
cas(V,Expected,NewValue)
- if V == E
V = New
otherwise try again or fail
- CPU原语支持 所以不用担心 第一二步之间被其他线程抢先
- JUC 常用锁
CountDownLatch,CyclicBarrier,Phaser,ReadWriteLock,Semaphore,Exchanger,LockSupport
- wait,notify生产者消费者代码
public class MyContainer<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int Max = 10;
public synchronized void put (T t){
while(lists.size() == Max){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
lists.add(t);
this.notifyAll(); //通知消费者进行消费
}
public synchronized T get (){
T t = null;
while(lists.size() == 0){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
t = lists.removeFirst();
this.notifyAll();
return t;
}
public static void main(String[] args) {
MyContainer<String> c = new MyContainer<>();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
for(int j =0;j<5; j++) System.out.println(c.get());
},"c"+i).start();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//生产者线程
for (int i = 0; i < 2; i++) {
new Thread(() ->{
for(int j =0;j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
},"p"+i).start();
}
}
}
- ReentrantLock的Condition的本质是什么?
不同的等待队列,new Condition就多创建一个等待队列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了