跳至主要內容

1.并发编程挑战

引领潮流大约 2 分钟java并发编程艺术juc

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"