热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

并发编程入门:初探多任务处理技术

并发编程入门:探索多任务处理技术并发编程是指在单个处理器上高效地管理多个任务的执行过程。其核心在于通过合理分配和协调任务,提高系统的整体性能。主要应用场景包括:1)将复杂任务分解为多个子任务,并分配给不同的线程,实现并行处理;2)通过同步机制确保线程间协调一致,避免资源竞争和数据不一致问题。此外,理解并发编程还涉及锁机制、线程池和异步编程等关键技术。

什么是并发编程

简单的说,所谓的并发编程指的是同一台处理器“同时”处理多个任务。

并发的三种场景

1、分工

      合理的拆解不同的任务,并能分配到线程,使多个任务更高效的执行。

2、同步

      线程的执行依赖其他线程的执行结果。

3、互斥

      多个线程需要抢占共享资源。

并发问题的源头

多线程的出现虽然可以提高应用程序的执行效率,但是不可避免的,也会引入一些问题,这些问题的源头如下:

1、缓存带来的可见性问题

     由于CPU的读写速度远远大于内存的读写速度,故CPU利用缓存来缓和CPU和内存读写速度差异带来的问题;

     对于多核处理器,每个核都有独立的缓存,这样CPU在计算完数值后,将数值存入缓存,但是写到内存的时机是不确定的,因此会发生缓存可见性问题

     技术图片

             示例:如下程序,预期结果为20000,但实际执行结果为10000~20000之间

public class Add {
    private static long count = 0;
    
    public static long testAdd() throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <10000; i++) {
                    count ++;
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <10000; i++) {
                    count ++;
                }
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        return count;
    }
}

2、线程切换带来的原子性问题

      操作系统支持的最大线程数要远远大于操作系统核数,这是为了缓解CPU的IO速度差异,采用了分时复用机制。

      原子性问题的原因是:多线程操作共享变量时,一个线程还未对该变量操作完成,由于分时复用策略,另外一个线程获取了执行权,这个线程获取到的值有可能是错误的。

      常见的面试题:long型的变量在32位系统的高并发应用程序中,为什么会有线程安全问题?

      原因:long型变量是64位的,32位操作系统对long型变量赋值的操作步骤为:先对高32位赋值,再对低32位赋值;这样,如果中间发生了线程切换,就可能获取到错误的值

3、编译优化带来的有序性问题

      有序性问题是有编译器会对我们的指令进行优化重排序,这样不会影响最终的执行结果;但是有时还是会发生一些意想不到的问题;

      举例:单例模式下双重检查

public class Singleton {
    private static Singleton instance = null;
    
    public static Singleton getInstance() {
        if (null == instance) {
            synchronized (Singleton.class) {
                if (null == instance) {
                    instance = new Singleton();
                    return instance;
                }
            }
        }
        
        return instance;
    }
}

       第一层判空是为了避免加锁导致的性能问题;第二层判空是为了避免创建多个实例;这看起来并没有什么问题,但是由于编译器指令重排,可能会出现问题。

            正常创建实例的指令顺序为:分配内存--->内存初始化---->变量指向内存地址

            编译优化后指令顺序可能为:分配内存--->变量指向内存地址--->内存初始化

            如果线程执行到第二步的时候被剥夺执行权,另一个线程判空的结果为非空,从而直接返回了instance;由于此时instance未初始化,可能会导致空指针异常

     并发带来的三个问题

       1、安全性问题

             安全性问题的本质就是数据的正确性,为了保证线程安全,应该避免同一时刻不同线程操作共享数据。

       2、活跃性问题

            饥饿:由于线程优先级低等原因,可能会导致线程一直不能被执行

            死锁:线程竞争共享资源,并且互相持有对方的锁,造成多个线程一直等待,造成死锁。

            活锁:和死锁相反,活锁是由于“过于谦让”导致的问题;线程访问共享资源,发现另一个线程也需要访问共享资源,于是退出,等待重试;

                       另外的线程也是如此,因此出现活锁问题。

       3、性能问题 

             锁的过度使用,导致程序串行执行的范围过大,这样就违背了并发编程的优势;

             在实际应用中,应尽量减少不必要锁的使用,尽量减少串行

并发编程001 --- 初识并发


推荐阅读
  • 在Python网络编程中,多线程技术的应用与优化是提升系统性能的关键。线程作为操作系统调度的基本单位,其主要功能是在进程内共享内存空间和资源,实现并行处理任务。当一个进程启动时,操作系统会为其分配内存空间,加载必要的资源和数据,并调度CPU进行执行。每个进程都拥有独立的地址空间,而线程则在此基础上进一步细化了任务的并行处理能力。通过合理设计和优化多线程程序,可以显著提高网络应用的响应速度和处理效率。 ... [详细]
  • React项目基础教程第五课:深入解析组件间通信机制 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • JavaScript XML操作实用工具类:XmlUtilsJS技巧与应用 ... [详细]
  • 本文详细介绍了在C#编程环境中绘制正方形图像的技术和实现方法,通过具体示例代码帮助读者理解和掌握相关技巧。内容涵盖从基础概念到实际应用的各个方面,适合初学者和有一定经验的开发者参考。希望对您的C#学习之旅有所帮助,并激发您进一步探索的兴趣。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • 捕获并处理用户输入数字时的异常,提供详细的错误提示与指导
    在用户输入数字时,程序能够有效捕获并处理各种异常情况,如非法字符或格式错误,并提供详尽的错误提示和操作指导,确保用户能够准确输入有效的数字数据。通过这种方式,不仅提高了程序的健壮性和用户体验,还减少了因输入错误导致的系统故障。具体实现中,使用了Java的异常处理机制,结合Scanner类进行输入读取和验证,确保了输入的合法性和准确性。 ... [详细]
  • C++入门必备:首个博客知识点汇总
    本文总结了C++初学者需要掌握的关键知识点,特别强调了成员类型的区分。其中,protected成员与private成员在本类中的作用相同,但protected成员允许派生类的成员函数访问,而private成员则不允许。此外,文章还介绍了其他重要的C++基础概念,如类的构造函数、析构函数以及继承机制,为初学者提供了一个全面的学习指南。 ... [详细]
  • 二叉树的直径是指树中任意两个叶节点之间最长路径上的节点数量。本文深入解析了计算二叉树直径的算法,并提出了一种优化方法,以提高计算效率和准确性。通过详细的案例分析和性能对比,展示了该优化算法在实际应用中的优势。 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 自动加载机制在命名空间和类文件中的应用与优化
    自动加载机制在命名空间和类文件中的应用与优化 ... [详细]
  • 利用 PHP APICommonUrl 中转实现 jQuery JSONP 请求优化 ... [详细]
  • 在使用 `requests` 库进行 HTTP 请求时,如果遇到 `requests.exceptions.SSLError: HTTPSConnectionPool` 错误,通常是因为 SSL 证书验证失败。解决这一问题的方法包括:检查目标网站的 SSL 证书是否有效、更新本地的 CA 证书库、禁用 SSL 验证(不推荐用于生产环境)或使用自定义的 SSL 上下文。此外,确保 `requests` 库和相关依赖项已更新到最新版本,以避免潜在的安全漏洞。 ... [详细]
author-avatar
墨尔本晴上残留的余温丶_856
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有