1.并发编程挑战
大约 2 分钟
1.上下文切换
多线程一定快吗?
不一定 当并发操作执行操作循环累加不超百万次时,速度比串行执行慢。 原因是线程创建和上下切换的开销
测量上下文切换和时长
Lmbench3 测量上下文切换的时长 vmstat 测量上下文切换次数
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 127876 398928 2297092 0 0 0 4 2 2 0 0 99 0 0
0 0 0 127868 398928 2297092 0 0 0 0 595 1171 0 1 99 0 0
#CS(Content Switch)表示上下文切换的次数,从上面的测试结果中我们可以看到,上下文 每1秒切换1000多次。
如何减少上下文切换
1、无锁并发编程 : 数据id按照hash算法分段取模,不同线程处理不同数据段 2、CAS算法: atomic包使用cas算法更新数据 3、使用最少线程 4、使用协程: 单线程多任务调度
实战案例
# 用jstack命令dump线程信息,看看pid为3117的进程
sudo -u admin /opt/ifeve/java/bin/jstack 31177 > /home/tengfei.fangtf/dump17
# 统计所有线程分别处于什么状态
grep java.lang.Thread.State dump17 | awk '{print $2$3$4$5}' | sort | uniq -c
39 RUNNABLE
21 TIMED_WAITING(onobjectmonitor)
6 TIMED_WAITING(parking)
51 TIMED_WAITING(sleeping)
305 WAITING(onobjectmonitor)
3 WAITING(parking)
# 打开dump文件 查看WAITING状态
"http-0.0.0.0-7001-97" daemon prio=10 tid=0x000000004f6a8000 nid=0x555e in
Object.wait() [0x0000000052423000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007969b2280> (a org.apache.tomcat.util.net.AprEndpoint$Worker)
at java.lang.Object.wait(Object.java:485)
at org.apache.tomcat.util.net.AprEndpoint$Worker.await(AprEndpoint.java:1464)
- locked <0x00000007969b2280> (a org.apache.tomcat.util.net.AprEndpoint$Worker)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1489)
at java.lang.Thread.run(Thread.java:662)
# 减少工作线程数
WAITING的线程少了,系统上下文切换的次数就会少, 因为每一次从 WAITTING到RUNNABLE都会进行一次上下文的切换
2.死锁
避免死锁方法 1、避免一个线程获取多个锁 2、避免一个线程在所内同时占有多个资源,尽量保证每个锁只占用一个资源 3、尝试使用定时锁 lock.tryLock(timeout) 4、加锁解锁在一起
//测试死锁
public class DeadLockDemo {
private Object A = new Object();
private Object B = new Object();
private Runnable run1 = new Runnable() {
@Override
public void run() {
synchronized (A){
try {
Thread.sleep( 2000 );
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (B){
System.out.println("1");
}
}
}
};
private Runnable run2 = new Runnable() {
@Override
public void run() {
synchronized (B){
synchronized (A){
System.out.println("2");
}
}
}
};
public static void main(String[] args){
new DeadLockDemo().deadLock();
}
private void deadLock(){
new Thread( run1 ).start();
new Thread( run2 ).start();
}
}
3.资源限制挑战
资源限制的挑战: 程序的执行速度受限于计算机硬件资源或软件资源
引发问题: 代码并发执行,受限于资源,仍然串行执行,反而更慢,因为增加上线问调度和资源调度时间
根据资源受限情况调整并发度(并发线程数)
硬件资源:集群
软件资源:资源池复用
juc编程源码
https://github.com/yinlingchaoliu/juc tag "dead lock"