zoukankan      html  css  js  c++  java
  • 第一章 并发编程的挑战

     并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最大限度地并发执行,在进行并发编程时,如果希望通过多线程执行任务让程序运动得更快,会面临非常多的挑战,比如上下文切换的问题、死锁的问题,以及受限于硬件和软件的资源限制问题。

    挑战一:上下文切换

    多线程一定比单线程快么?

    public class ConcurrencyTest {
    
        private static final long count = 10001;
    
        public static void main(String[] args) throws InterruptedException {
            concurrency();
            serial();
        }
    
        private 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--;
            }
            thread.join();
            long time = System.currentTimeMillis() - start;
            System.out.println("concurrency:" + time + "ms, b = " + b);
        }
    
        private 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 + ", a=" + a);
        }
    }

    输出

    答案是并不一定,当测试量达到一百万的时候,并发才能比串行优势点(本代码环境结果);

    线程创建和上下文切换都是需要开销的。

    如何减少上下文的切换?

    • 无锁并发编程:可以使用一些方法避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
    • CAS算法:Java的Atomic包使用CAS算法更新数据,而不需要加锁。
    • 使用最少线程:避免创建不需要的线程。
    • 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

     

    挑战二:死锁

    public class DeadLockDemo {
        
        private static String A = "A";
        private static String B = "B";
    
        public static void main(String[] args) {
            new DeadLockDemo().deadLock();
        }
        
        private void deadLock(){
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (A){
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e){
                            e.printStackTrace();
                        }
                        synchronized (B){
                            System.out.println("1");
                        }
                    }
                }
            });
    
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (B){
                        synchronized (A){
                            System.out.println("2");
                        }
                    }
                }
            });
            thread1.start();
            thread2.start();
        }
    }

    避免死锁的几个常见方法:

    • 避免一个线程同时获取多个锁
    • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占一个资源
    • 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
    • 对于数据库锁,加锁和解锁必须在一个数据库连接里

    挑战三:资源限制的挑战

    (1) 什么是资源限制?

    指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。

    (2) 资源限制引发的问题?

    在并发编程中,将代码执行速度加快的原则是将代码中串行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的时间。

    (3)如何解决资源限制的问题?

    对于硬件限制,可以考虑集群并行执行程序。既然单机的资源有限制,就让程序在多机上运行。比如使用ODPS、Hadoop或者自己搭建服务器集群;

    对于软件限制,可以考虑使用资源池将资源复用。比如使用连接池将数据库和Socket连接复用,或者在调用对方webService接口获取数据时,只建立一个连接。

    (4)如何在资源限制的情况下进行并发编程?

    根据不同的资源限制调整程序的并发度,比如下载文件程序依赖于两个资源——宽带和硬盘读写速度。有数据库操作时,设计数据库连接数,如果SQL语句执行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。

  • 相关阅读:
    SPSS-Friedman 秩和检验-非参数检验-K个相关样本检验 案例解析
    SPSS-多重响应-频率和交叉表案例分析(问卷调查分析)
    SPSS--回归-多元线性回归模型案例解析
    深入理解RunLoop
    杂七杂八集合
    单元测试
    笔记
    http断点续传
    iOS性能优化
    群聊协议
  • 原文地址:https://www.cnblogs.com/hzzjj/p/9678064.html
Copyright © 2011-2022 走看看