第一章 并发编程的挑战

2020-04-21  本文已影响0人  巴巴11

The Art of Java Concurrency Programming.

从JDK source code、JVM、CPU等多角度分析。

并发编程遇到的挑战。会遇到的问题。如何解决。

目的:让程序运行的更快。

误区:并不是线程越多性能越好。(线程创建的开销,上下文切换的开销,死锁的问题,受限于硬件、网络带宽等软件资源问题)

上下文切换:
单核CPU或者多核都支持多线程执行任务,CPU为每个线程分配CPU时间片来执行。(时间片一般几十毫秒)(时间片分配算法)
CPU执行完一个时间片切换到另外一个时间片(切换前会保存上一个任务的状态)。
任务从保存到再加载的过程就是一次上下文切换。

如何减少上下文切换:

多线程竞争锁,会引起上下文切换,可以避免使用锁,比如将数据的ID按照Hash算法取模分段。不同的线程处理不同段的数据。(concurrencyhashmap的原理)

Atomic包使用CAS算法来同步更新数据,不需要加锁。

尽量避免创建更多的线程。

在单线程里实现多任务的调度。在单线程里维持多个任务的切换。

常用命令:

# jstack dump thread 
$ sudo -u admin /opt/tools/java/bin/jstack 31777 > /home/wh/dump123
$ vi /home/wh/dump123

# 线程从Wating 到 Running状态都会进行一次上下文切换

死锁:
锁的使用不当可能会带来死锁问题。

避免死锁:

软件资源限制对并发的影响:
硬件资源限制有带宽的上传/下载速度、硬盘的读写速度、CPU的处理速度。
软件资源有数据库的连接数和socket连接数等。

如何解决资源限制的问题:
使用集群(搭建Hadoop集群,不同机器处理不同数据,数据ID%机器数得到机器编号)。
软件资源可以使用连接池技术和socket连接复用。

建议:
尽可能使用并发包提供的并发容器和工具类来解决问题。

多线程一定比单线程快吗?code:

package chapter1;

/**
 * 多线程一定比单线程快吗?
 *
 * 在百万次规模内,多线程比串行要慢!!!
 * 线程的创建开销;线程上下文切换的开销;
 *
 * Lmbench3可以测量上下文切换的时长
 * vmstat可以测量上下文切换的次数
 */
public class ConcurrencyTest {
    private static final long count = 10000l;

    public static void main(String[] args) throws InterruptedException {
        concurrency();
        serial();
    }

    static void concurrency() throws InterruptedException {
        long start = System.currentTimeMillis();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                int a = 0;
                for (long i = 0; i < count; i++) {
                    a += 5;
                }
            }
        });
        thread.start();
        int b = 0;
        for (long i = 0; i < count; i++) {
            b--;
        }
        long time = System.currentTimeMillis() - start;
        thread.join();
        System.out.println("concurrency : " + time + "ms, b = " + b);
    }

    static void serial() {
        long start = System.currentTimeMillis();
        int a = 0;
        for (long i = 0; i < count; i++) {
            a += 5;
        }
        int b = 0;
        for (long i = 0; i < count; i++) {
            b--;
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("serial : " + time + "ms, b = " + b);
    }
}

死锁code:

package chapter1;

/**
 * 死锁问题
 */
public class DeadLock {
    static String A = "A";
    static String B = "B";

    void deadLock() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (A) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("A");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("B");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

上一篇下一篇

猜你喜欢

热点阅读