(二)并发编程的优缺点

1.并发编程的优点:

        面对复杂业务模型,并行程序比串行程序更适应业务需求,而并发编程更吻合这种业务拆分,正是因为这些优点,使得多线程技术能够得到重视,也是一名CS学习者应该啊掌握的;

  • 充分利用多喝CPU的计算能力
  • 方便进行业务拆分,提升应用性能

2.并发编程的缺点:

       多线程技术有这么多的好处,难道就没有一点缺点,就在任何场景下就一定适用么?很显然不是

2.1频繁的上下文切换

       时间片是CPU分配给各个线程时间,因为时间非常短,所以CPU不断通过切换线程,让我们觉得多个线程是同时执行的,时间片一般是几十毫秒.而每次切换时,都要保存当前的状态,以便能够恢复先前状态,而这个切换是非常损耗性能的,过于频繁反而无法发挥多线程编程的优势.通常减少上下文切换可以采用无锁并发编程,CAS算法,使用最小的线程和使用协程.

  • 无锁并发编程:可以参照concurrentHashMap锁分段的思想,不同的线程处理不同段的数据,这样在多线程竞争的条件下,可以减少上下文切换.
  • CAS算法:利用Atomic下使用CAS算法来更新数据,使用了乐观锁,可以有效的减少一部分不必要的锁竞争带来的上下文切换.
  • 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多的线程,这样会造成大量的线程都处于等待状态.
  • 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换.

2.2线程安全

      多线程编程中最难把握的就是临界区线程安全问题,稍微不注意就会出现死锁的情况出现,一旦产生死锁就会造成系统功能不可用.

public class DeadLockDemo {
    private static String resource_a = "A";
    private static String resource_b = "B";

    public static void main(String[] args) {
        deadLock();
    }

    private static void deadLock() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_a) {
                    System.out.println("get resource a");
                    try {
                        Thread.sleep(3000);
                        synchronized (resource_b) {
                            System.out.println("get resource b");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_b) {
                    System.out.println("get resource b");
                    synchronized (resource_a) {
                        System.out.println("get resource a");
                    }
                }
            }
        });
        threadA.start();
        threadA.start();
    }

}

那么,通常可以用如下方式避免死锁的情况

  1. 避免一个线程同时获得多个锁.
  2. 避免一个线程在锁内部占有多个资源,尽量保证每个锁只占有一个资源.
  3. 尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时,当前线程不会阻塞.
  4. 对于数据锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况.

所以,如何正确的使用多线程编程技术有很大的学问,比如如何保证线程安全,如何正确理解由于JMM内存模型在原子性,有序性,可见性带来的问题,比如数据脏读,DCL等这些问题(在后续篇幅会讲述).在学习多线程编程技术的过程中会让你收获颇丰.所以要重视多线程编程.

原文地址:https://www.cnblogs.com/pingping-joe/p/9186930.html