美文网首页想法
关于 java 多线程,你需要知道的一些基础知识

关于 java 多线程,你需要知道的一些基础知识

作者: shengjk1 | 来源:发表于2024-06-04 17:39 被阅读0次

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

一、前言

俗话说的好,学好数理化,走遍天下都不怕。也就是说总有一些基础中的基础,学好了这些就可以起到事半功倍的效果

二、线程基础

2.1 CPU时间片

CPU时间片是操作系统中一个重要概念,它指的是操作系统分配给每个进程在CPU上执行的时间长度。

在多任务处理系统中,CPU时间片用于实现多进程之间的轮转调度,确保每个进程都有机会执行并且不会长时间占用CPU。

CPU分配给各个线程/进程的时间片非常短,CPU通过不停地切换线程/进程执行(而这种切换如果太多会严重影响多线程程序的执行效率),让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)

2.2 减少上下文切换

既然多线程上下文切换,会消耗导致程序执行效率降低,那么如何减少切换呢?
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程

1. 无锁并发编程
多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的D按照Hsh算法取模分段,不同的线程处理不同段的数据。

2. CAS算法
Java的Atomic包使用CAS算法来更新数据,而不需要加锁。

在x86架构下,底层通常使用CMPXCHG指令来实现CAS操作。以下是在x86汇编中简单示例:

lock cmpxchg [destination], register
  • lock: 这个前缀指示CMPXCHG操作是原子的,即在执行期间不会被中断。
  • cmpxchg: 比较目标内存位置的值和寄存器中的值,如果相等则将寄存器中的值写入目标内存位置,否则不执行任何操作。
  • [destination]: 是要操作的目标内存位置。
  • register: 是一个寄存器,用来存放要写入目标内存位置的值。

在实际执行时,CPU会比较目标内存地址中的值和寄存器的值,如果相等,则将寄存器的值写入目标内存地址,并返回成功。否则不进行写入操作,返回失败。整个过程是原子的,不会被其他线程的操作打断。

3. 使用最少线程
避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。

4. 协程
在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

2.3 死锁

死锁是指两个或多个进程(或线程)相互等待对方持有的资源,导致它们都无法继续执行的情况。在死锁状态下,没有任何一个进程能够继续执行,系统变得无响应。

public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1: Holding lock 1...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
                System.out.println("Thread 1: Waiting for lock 2...");
                synchronized (lock2) {
                    System.out.println("Thread 1: Holding lock 1 and lock 2...");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2: Holding lock 2...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
                System.out.println("Thread 2: Waiting for lock 1...");
                synchronized (lock1) {
                    System.out.println("Thread 2: Holding lock 1 and lock 2...");
                }
            }
        });

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

如何避免死锁

1. 避免一个线程同时获取多个锁。

2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。

3. 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。

4. 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

2.4 资源限制

这里的资源限制包括硬件资源限制和软件资源限制。在进行多线程编程时,要考虑资源限制。

举个例子:某机器的宽带只有 1Mb/s,某资源下载速度为 500KB/s,你用 10个线程,下载速度也不会变成 5000KB/s,最多为 1Mb/s。

另外,如果将代码改成多线程,但由于资源限制,导致其仍然以单线程方式执行,那这个程序会更慢,因为相比于单线程,增加了上下文切换和资源调度的时间。这一点需要额外注意!

三、其他

3.1 CPU时间片优势

虽然线程或进程切换会消耗一定的时间和资源,但使用CPU时间片的方式有一些重要的原因和优势,以确保系统能够高效地运行和满足多任务处理的需求:

  1. 公平性和资源共享:使用时间片可以确保系统中的每个线程或进程都能够获得公平的CPU时间,并避免其中一个线程长时间独占 CPU 而导致其他任务得不到执行的情况。
  2. 多任务处理:时间片允许操作系统在不同的线程或进程之间进行切换,从而实现多任务处理。这种方式使得多个任务能够交替执行,提高系统的并发性能。
  3. 响应速度:通过时间片轮转,每个线程都有机会获得 CPU 时间,这有助于系统快速响应用户操作和事件,提高系统的整体响应速度。
  4. 资源利用率:通过合理设置时间片长度和调度算法,可以有效利用 CPU 资源,确保 CPU 在每个时间片内都被充分利用。
  5. 避免饥饿现象:使用时间片可以防止某些线程长时间无法获取 CPU 资源而产生饥饿现象,保证系统的公平性和稳定性。 尽管线程或进程的切换会有一定的开销,但通过合理优化调度算法和提高上下文切换效率等方式,可以尽量减少这种开销,从而确保系统在提供公平性、多任务处理、快速响应等方面具有较高的效率和性能。因此,CPU 时间片机制仍然是一种非常有效的多任务处理方式,被广泛应用于操作系统中。

四、总结

多线程编程在提高系统性能和并发性方面具有重要作用,但也面临着一些挑战,如上下文切换的开销、死锁的风险和资源限制等。通过合理使用CPU时间片、减少上下文切换、避免死锁和考虑资源限制,可以提高多线程编程的效率和稳定性。

相关文章

  • 通过了解RejectedExecutionException来分

    观看本文章之前,最好看一下这篇文章熟悉下ThreadPoolExecutor基础知识。1.关于Java多线程的一些...

  • Java多线程高级特性(JDK8)

    [TOC] 一、Java多线程 1.Java多线程基础知识 Java 给多线程编程提供了内置的支持。一条线程指的是...

  • Java实现两个线程交替打印1-100

    这道java基础题主要考察的是对java并发基础知识的掌握,一般需要掌握多线程中的wait(),notify(),...

  • 多线程基础

    1.关键术语和多线程基础介绍 关于多线程的基础知识请卡如下的文章: 高并发Java(1):前言 2.基础 参考:高...

  • 关于多线程面试的一些问题

    关于多线程的一些问题(java) 标签(空格分隔): 并发 面试 多线程 java中有几种方法可以实现一个线程? ...

  • 多线程--同步与锁

    同步与锁 上一篇中,笔者介绍了Java多线程的基础知识,主要讲解了进程/线程的区别、Java多线程的创建、Java...

  • Java多线程:生命周期,实现与调度

    前面几篇文章为Java多线程做足了铺垫,这篇终于到了正题,一起学习一下Java多线程的基础知识。 1. Java线...

  • Android开发 Java线程基础

    简介 本篇文章是带大家了解 Java多线程的基础知识.主要内容: 介绍多线程的概念, 了解多线程的优点, 状态, ...

  • 并发编程艺术-4

    本文主要介绍的Java 并发编程的基础知识, 其中包括了:线程是什么? 为什么需要多线程? 线程的状态和相关操作。...

  • 最强大的Android线程池框架

    背景 大家都知道在我们的开发中永远都离不开多线程,对于我们为什么要使用多线程,多线程的使用和多线程的一些基础知识这...

网友评论

    本文标题:关于 java 多线程,你需要知道的一些基础知识

    本文链接:https://www.haomeiwen.com/subject/ezvyqjtx.html