Java多线程编程理解与应用。

多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level  multithreading)或同时多线程(Simultaneous  multithreading)处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。

Java对多线程的支持是非常强大的,他屏蔽掉了许多的技术细节,让我们可以轻松的开发多线程的应用程序。
Java里面实现多线程,有2个方法:
使用 Thread类

class MyThread{ 
    public static void main(String[] args){ 
        new Thread(){
            public void run(){ 
                //写上线程需要执行的代码
            } 
        }.start();
    } 
}

使用 Runnable

class MyThread{
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                 //写上线程需要执行的代码
            }
        }).start();
    }  
}

并发编程适用于什么场景?

如果问你选择多线程的原因就是一个【快】字,面试也就不会出那么多幺蛾子了。你有没有问过你自己

1.并发编程在所有场景下都是快的吗?

2.知道它很快,何为快?怎样度量?

想知道这两个问题的答案,我们需要一个从【定性】到【定量】的分析过程

使用多线程就是在正确的场景下通过设置正确个数的线程来最大化程序的运行速度(我感觉你还是啥也没说)

将这句话翻译到硬件级别就是要充分的利用 CPU 和 I/O 的利用率



两个正确得到保证,也就能达到最大化利用 CPU 和 I/O的目的了。最关键是,如何做到两个【正确】?

在聊具体场景的时候,我们必须要拿出我们的专业性来。送你两个名词 buff 加成

  • CPU 密集型程序

  • I/O 密集型程序

CPU 密集型程序

一个完整请求,I/O操作可以在很短时间内完成, CPU还有很多运算要处理,也就是说 CPU 计算的比例占很大一部分

假如我们要计算 1+2+....100亿 的总和,很明显,这就是一个 CPU 密集型程序

在【单核】CPU下,如果我们创建 4 个线程来分段计算,即:

1.线程1计算 [1,25亿)

2....... 以此类推

3.线程4计算 [75亿,100亿]

我们来看下图他们会发生什么?



由于是单核 CPU,所有线程都在等待 CPU 时间片。按照理想情况来看,四个线程执行的时间总和与一个线程5独自完成是相等的,实际上我们还忽略了四个线程上下文切换的开销

所以,单核CPU处理CPU密集型程序,这种情况并不太适合使用多线程

此时如果在 4 核CPU下,同样创建四个线程来分段计算,看看会发生什么?



每个线程都有 CPU 来运行,并不会发生等待 CPU 时间片的情况,也没有线程切换的开销。理论情况来看效率提升了 4 倍

所以,如果是多核CPU 处理 CPU 密集型程序,我们完全可以最大化的利用 CPU 核心数,应用并发编程来提高效率

I/O密集型程序

与 CPU 密集型程序相对,一个完整请求,CPU运算操作完成之后还有很多 I/O 操作要做,也就是说 I/O 操作占比很大部分

我们都知道在进行 I/O 操作时,CPU是空闲状态,所以我们要最大化的利用 CPU,不能让其是空闲状态

同样在单核 CPU 的情况下:



从上图中可以看出,每个线程都执行了相同长度的  CPU 耗时和 I/O 耗时,如果你将上面的图多画几个周期,CPU操作耗时固定,将 I/O 操作耗时变为 CPU 耗时的 3  倍,你会发现,CPU又有空闲了,这时你就可以新建线程 4,来继续最大化的利用 CPU。

综上两种情况我们可以做出这样的总结:

线程等待时间所占比例越高,需要越多线程;线程CPU时间所占比例越高,需要越少线程。


创建多少个线程合适?

面试如果问到这个问题,这可是对你理论和实践的统考。想完全答对,你必须要【精通/精通/精通】小学算术

从上面知道,我们有 CPU 密集型和 I/O 密集型两个场景,不同的场景当然需要的线程数也就不一样了

CPU 密集型程序创建多少个线程合适?

有些同学早已经发现,对于 CPU 密集型来说,理论上 线程数量 = CPU 核数(逻辑) 就可以了,但是实际上,数量一般会设置为 CPU 核数(逻辑)+ 1, 为什么呢?

《Java并发编程实战》这么说:

计算密(CPU)集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个“额外”的线程,可以确保在这种情况下CPU周期不会中断工作。

所以对于CPU密集型程序, CPU 核数(逻辑)+ 1 个线程数是比较好的经验值的原因了

I/O密集型程序创建多少个线程合适?

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java