java并发和多线程之并发面临的性能问题

发布于:2024-07-17 ⋅ 阅读:(138) ⋅ 点赞:(0)

学习并发编程之前一定要学JVM

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

1.上下文切换问题

1.1 什么是上下文切换

CPU 过时间 片分配算法来循 环执 行任 ,当前任 务执 行一个 时间 片后会切 到下一个任务 。但是,在切 前会保存上一个任 的状 ,以便下次切 个任 务时 ,可以再加 载这个任务 的状 。所以任 从保存到再加 程就是一次上下文切

1.2 问题

多线程不一定快

为线程有建和上下文切的开,上下文切换的开销比直接用单线程大,因为在多线程中,需要保存和恢复更多的上下文信息。过多的上下文切换会降低系统的运行效率,因此需要尽可能减少上下文切换的次数。

1.3 如何减少上下文的切换

减少上下文切 的方法有无 发编 程、 CAS 算法、使用最少 线 程和使用 程。
· 发编 程。多 线 锁时 ,会引起上下文切 ,所以多 线 理数据 ,可以用一
法来避免使用 ,如将数据的 ID 按照 Hash 算法取模分段,不同的 线 理不同段的数据。
·CAS 算法。 Java Atomic 包使用 CAS 算法来更新数据,而不需要加
· 使用最少 线 程。避免 建不需要的 线 程,比如任 很少,但是 建了很多 线 程来 理,
会造成大量 线 程都 于等待状
· 程:在 单线 程里 实现 多任 度,并在 单线 程里 持多个任 务间 的切

2.死锁

2.1 什么叫做死锁

        死锁是指两个或两个以上的进程(或线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

2.2 死锁产生的条件

(1)互斥条件:一个资源每次只能被一个进程使用。
(2)占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不可强行占有:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

2.3 如何解除死锁

· 避免一个 线 程同 时获 取多个
· 避免一个 线 程在 内同 占用多个 源,尽量保 每个 只占用一个 源。
· 尝试 使用定 时锁 ,使用 lock.tryLock timeout )来替代使用内部 机制。
· 于数据 库锁 ,加 和解 在一个数据 库连 接里,否 会出 的情况。

3. 资源限制的挑战

3.1 什么是资源限制

        资源限制是指在 行并 发编 ,程序的 行速度受限于 算机硬件 源或 源。 例如,服务 器的 带宽 只有 2Mb/s ,某个 源的下 速度是 1Mb/s 每秒,系 10 线 程下 载资
源,下 速度不会 10Mb/s ,所以在 行并 发编 ,要考 虑这 源的限制。硬件 源限
制有 带宽 的上 / 速度、硬 盘读 写速度和 CPU 理速度。 源限制有数据
数和 socket 接数等。

3.2 资源限制引发的问题

        
        在并发编 程中,将代 码执 行速度加快的原 是将代 中串行 行的部分 成并 发执 行,
但是如果将某段串行的代 发执 行,因 受限于 源,仍然在串行 行, 这时 候程序不
会加快 行,反而会更慢,因 增加了上下文切 度的 时间 。例如,之前看到一段程
序使用多 线 程在 公网并 地下 理数据 CPU 利用率达到 100% ,几个小 都不
能运行完成任 ,后来修改成 单线 程,一个小 行完成了。

3.3 如何解决资源限制问题

        对于硬件 源限制,可以考 使用集群并行 行程序。既然 机的 源有限制,那么就
程序在多机上运行。比如使用 ODPS Hadoop 或者自己搭建服 器集群,不同的机器 理不同
的数据。可以通 数据 ID% 机器数 算得到一个机器 号,然后由 对应编 号的机器
笔数据。
        对于 源限制,可以考 使用 源池将 源复用。比如使用 接池将数据 Socket
接复用,或者在 webservice 接口 取数据 ,只建立一个 接。

3.4 在资源限制情况下进行并发编程

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

拓展:CAS算法(非常重要,后面一定用到)

CAS(Compare And Swap)算法是一种用于实现并发控制的原子操作,主要用于多线程环境下的无锁算法和数据结构,以保证并发安全性。以下是对CAS算法的详细解释:

(1)CAS算法的基本概念

  • 定义:CAS算法通过比较内存中的值和预期值,如果相等则将新值写入内存,否则不做任何操作。它是一种轻量级的同步机制,能够在不使用锁(如synchronized、Lock)的情况下,对共享数据进行线程安全的操作。
  • 操作数:CAS算法涉及三个主要操作数——需要读写的内存位置V、需要进行比较的预期值A和新值B。

(2)CAS算法的工作原理

  1. 读取内存值:首先,CAS算法会读取要更新的内存位置V的当前值。
  2. 比较内存值和预期值:然后,将预期值A与读取到的内存值进行比较。
  3. 写入新值:如果两者相等,说明该位置的值在读取到之后没有被其他线程修改过,此时将新值B写入内存位置V。如果两者不相等,则说明该位置的值已经被其他线程修改,此时CAS操作失败,通常需要重新尝试。

(3)CAS算法的实现

  • 硬件支持:CAS算法的原子性操作依赖于硬件的支持,通常是通过处理器提供的原子指令来实现。
  • Java实现:在Java中,CAS算法的实现主要依赖于sun.misc.Unsafe类(在Java 9及以后版本中,该类的部分功能被封装在jdk.internal.misc.Unsafe中),它提供了一些底层操作方法来实现CAS算法。此外,Java 5之后,JDK提供了java.util.concurrent.atomic包,其中的原子类(如AtomicInteger、AtomicLong等)就是基于CAS算法实现的。

(4)CAS算法的优点

  1. 非阻塞性:CAS算法是一种非阻塞算法,一个线程失败或挂起并不会导致其他线程也失败或挂起,这有助于提高并发性能。
  2. 避免死锁:由于CAS算法不使用锁,因此可以避免传统锁机制中的死锁问题。
  3. 减少上下文切换:CAS算法减少了线程间的竞争,从而减少了上下文切换的开销。

(5)CAS算法的缺点

  1. ABA问题:在CAS算法中,如果共享数据的值在操作过程中被修改了两次,但是最终值又恢复为原始值,那么CAS算法无法检测出这种情况,可能导致数据异常。
  2. 循环时间长:在多线程竞争激烈的情况下,由于CAS算法是通过不断自旋来比较和更新共享数据的值,可能会导致线程长时间自旋,降低了性能。
  3. 只能保证一个共享变量的原子操作:如果操作多个共享变量,则需要使用其他同步机制来保证原子性。

(6)CAS算法的应用场景

CAS算法广泛应用于并发编程中,如实现无锁数据结构、实现线程安全的计数器等。在Java中,java.util.concurrent.atomic包下的原子类就是基于CAS算法实现的,它们提供了丰富的原子操作,方便开发者在多线程环境下进行并发编程。

综上所述,CAS算法是一种重要的并发控制机制,它通过比较和交换共享数据的值来保证线程安全,避免了传统锁机制中的一些问题,但同时也存在一些缺点和限制。在实际应用中,需要根据具体场景和需求来选择合适的并发控制机制。


网站公告

今日签到

点亮在社区的每一天
去签到