「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
Java并发
上下文切换
时间片是CPU分配给各个线程的时间,时间片非常短,CPU通过不停的切换线程执行,感觉多个线程是同时执行的。
任务从保存到再加载的过程就是一次上下文切换
构造方法不能用synchronized修饰,构造方法本身就是线程安全的。
为什么会存在并发执行比串行执行的速度要慢的情况?
因为线程有创建和上下文切换的开销。
如何减少上下文切换
无锁并发编程、CAS算法、最少线程、使用协程
- 无锁并发编程
多线程竞争锁会引起上下文切换。避免使用锁的解决方案,如将数据的ID按照Hash算法取模分段,不同的线程处理不同的数据。
- CAS算法
Java的Atomic包使用CAS算法来更新数据,不需要加锁。
- 最少线程
避免创建不需要的线程。
- 使用协程
在单线程里实现多任务的调度,以及多任务的切换。
引起死锁的条件
如何避免死锁
- 保证一个线程在同一时间只能获取一个锁。
- 避免一个线程在锁内同时占有多个资源,保证每个锁只占用一个资源。
- 尝试使用定时锁 lock.tryLock(timeout) 。
- 数据库锁加锁和解锁必须在一个数据库连接里。
synchronized底层原理剖析:
javac SynchronizedDemo.java
javap -c -s -v -l SynchronizedDemo.class
修饰代码块:
public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("synchronized 代码块");
}
}
}
同步代码块是
monitorenter和monitorexit指令实现的。
monitorenter:会尝试获取对象的锁,锁的计数器为0时,表示锁可以被获取,拿到锁后,计数器+1
monitorexit:将锁的计数器设为0,锁被释放。
修饰方法:
public class SynchronizedDemo2 {
public synchronized void method() {
System.out.println("synchronized 方法");
}
}
ACC_SYNCHRONIZED:表示该方法为同步方法。JVM 通过 ACC_SYNCHRONIZED 标识来判断一个方法是否为同步方法。
monitorenter和monitorexit指令 与 ACC_SYNCHRONIZED的本质都对monitor监视器的获取。