(一)并发编程的挑战
程序员文章站
2022-05-13 14:59:38
...
并发编程的目的是为了充分利用硬件资源,让程序跑的更快,但并不意味着开启更多的线程就能够实现这个目的,还需要考虑上下文切换、死锁的问题。
1.1 上下文切换
CPU通过时间片分配的方式来同时执行多个任务,一个任务执行一个时间片以后保存当前任务信息,然后加载另一个任务信息并切换到另一个任务,这就是一次上下文切换的过程。
减少上下文切换次数方法:
- 无所并发编程,多线程竞争锁会引起上下文切换,可以采取分段加锁;
- CAS算法,Atomic包使用CAS来更新数据;
- 使用最小线程,避免创建不必要线程;
- 协程,单线程实现多任务调度;
1.2 死锁
public class DeadLockDemo {
private static String A = "A";
private static String B= "B";
public static main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// 获取锁 A
synchronized (A) {
try {
// 休眠2秒再去获取锁B
Thread.currentThread().sleep(2000);
} catch(InterruptedException ie) {
e.printStackTrace();
}
// 获取锁B,此时线程t2可能已经获取到了锁B,所以在此等待锁B
synchronized (B) {
System.out.println(1);
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
// 获取锁B
synchronized (B) {
// 获取锁A,此时线程t1已经获取到了锁A,所以在此等待锁A
synchronized (A) {
System.out.println(2);
}
}
}
});
t1.start();
t2.start();
}
}
以上示例演示了造成死锁的过程:获取锁A的线程等待锁B,获取锁B的线程等待锁A,导致两线程同时等待,无法继续执行。
避免死锁的几个方法:
- 避免一个线程同时获取多个锁;
- 避免一个线程同时占用多个资源;
- 使用锁时,使用lock.tryLock(timeout)机制,超时获取不到则返回;
- 数据库锁,加锁和解锁必须在同一线程里;
1.3 资源限制
网络带宽、CPU、文件等资源限制,考虑使用“池化技术”,比如线程池、数据库连接池、Socket池。
上一篇: 网易滑动验证码