什么是并发编程?

前言并发编程的目的是为了提高程序的执行速度.但是并不意味着启动更多的线程会达到更好的并发效果,并发编程还会引起死锁 , 上下文频繁切换 , 线程不安全等问题.该问题主要介绍几种并发引来的问题及解决方案

一.上下文切换

1.1什么是上下文切换?

无论是单核还是多核cpu都是支持多线程执行代码的,cpu通过给每一个线程分配时间片,只有拿到时间片的线程才可以执行,通常时间片很短只有几十ms,让我们感觉是多个线程在并行操作.

1.2多线程一定快吗?

我们通过以下代码对比两者的执行速度

public class ConcurrentTest {
    private final static long times = 100000000;

    public static void main(String[] args) throws InterruptedException {
        concurrent();
        serial();
    }
    private static void concurrent() throws InterruptedException {
        long start = System.currentTimeMillis();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                long a = 0;
                for (int i = 0 ; i < times;i++) {
                   a++;
                }
            }
        });
        thread.start();
        long b = 0;
        for (int j = 0 ; j < times;j++ ){
            b++;
        }
        thread.join();
        long end = System.currentTimeMillis();
        System.out.println("concurrent cost:" +(end - start));
    }

    private static void serial() {
        long start = System.currentTimeMillis();
        long a = 0;
        for (int i = 0 ; i < times;i++) {
            a++;
        }
        long b = 0;
        for (int j = 0 ; j < times;j++ ){
            b++;
        }
        long end = System.currentTimeMillis();
        System.out.println("serial cost:" +(end - start));

    }
}

循环次数 串行时间/ms 并行时间
1万 0 2
10万 3 7
100万 6 13
1000万 14 11
1亿 145 76

从数据上发现,循环次数少时串行速度快,多时并行快,这是为什么呢?因为线程的创建与销毁和上下文切换带来的额外开销

1.3如何查看上下文切换?

可通过vmstat 查看上下文切换

1.4如何减少上下文切换?

  • 无锁编程 : 将处理的数据hash处理或取余等
  • CAS算法: juc 下的atomic包
  • 减少使用线程
  • 协程:单线程多任务调度(原生的java默认不支持,可引入其他框架)

1.5如何线上排查处理上下文切换

  1. 使用jstack获取线程信息
  2. 统计所有线程分别处于什么状态
  3. 打开dump文件查看处于WAITING的线程在做什么
  4. 减少JBOSS的工作线程数
  5. 重启JBOSS

二.死锁

当多线程对共享资源同时抢夺时,可能会因为相互等待资源释放,造成死锁

public class DeadLock {
    static class Q {}
    static class D {}
    private static Q q = new Q();
    private static D d = new D();
    public static void main(String[] args)  {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (q) {
                    System.out.println(Thread.currentThread().getName()+"拿到了Q");
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (d) {
                        System.out.println(Thread.currentThread().getName()+"拿到了D");
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (d) {
                    System.out.println(Thread.currentThread().getName()+"拿到了D");
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (q) {
                        System.out.println(Thread.currentThread().getName()+"拿到了Q");
                    }
                }
            }
        }).start();
    }
}

发布了235 篇原创文章 · 获赞 221 · 访问量 96万+

猜你喜欢

转载自blog.csdn.net/drdongshiye/article/details/95865104
今日推荐