多线程随想录——对线程的初步理解

    多进程和多线程

进程:系统中能独立运行并作为资源分配的基本单位。线程:CPU调度的基本单元。一个进程可以拥有多个线程,多个线程间共享进程的内存空间。

    从概念上,个人理解为:程序要想运行,必须开出一个进程来,那么创建一个进程就必须创建进程需要的存储空间,文件句柄,CPU资源等。而线程呢,只需要分配一些地址列表,CPU资源等,相对于进程的创建来说,消耗的资源就少了很多了。所以目前的软件更加的倾向于多线程,而非多进程。但是也不是已经不变的。多进程也好,多线程也好,都有他们的优点和缺点。拿线程共享内存空间来说,多进程还隔离内存空间呢,相互之间互不干扰。这还是优点呢,所以针对具体应用需要,来进行测试,哪个好就采取哪种。

    并发和并行

并发:都听说过时间片轮转法,CPU在等待线程的IO操作时,可以切换到其他线程,充分利用CPU的时间资源。可以说并发并不是同一时间做两件事,而是通过一系列的算法,CPU进行任务的操作。

并行:到了多核CPU的时代,同一时间做两件事成为了现实。所以两件事情并行处理得到了实现。

也就是说多线程主要和CPU有关。目前CPU多核的成本越来越低,所以多线程的程序更加的多见。

    多线程未必比单线程快

    使用多线程是需要成本的,首先拿程序来说,每创建一个线程,是需要消耗资源的。想想就知道了,每创建一个东西,肯定要花费一些材料的。而且多线程的上下文切换也是消耗巨大的。而且多线程的情况下是需要考虑很多东西的,需要开发成本。所以当用不着多线程时,就不要用多线程。如果程序的计算简单,程序执行速度快。多线程就不必要考虑了了。

      多线程下存在的问题

1、多线程管理。对线程需要管理,一般都采取线程池进行管理,那么问题来了,对于一个项目,应该怎么配置线程池呢?线程的最大数量应该设置为多少,怎样设置更加的合适。

2、多线程开发。由于线程之间的调度由操作系统来完成,程序员并不能控制线程的执行次序。线上遇到问题,问题的排查也十分考验程序员的知识面,经验和能力。

3、线程安全,线程之间共享内存变量,多个线程同时对一个变量进行操作会带来问题。

4、线程竞争。多个线程对同一资源竞争,可能会引发死锁的问题。


多线程应用

       在Java里创建线程的方式有三种,继承Thread方式,无返回值,每个线程不共享Thread的变量,实现Runanble接口方式,由Thread执行Runable.。共享变量,在java8里可以使用lambda,本质上仍旧是实现Runable接口方式。最后建立任务FutureTask,实现Callable接口,调用get方法取得返回值,得到该返回值,主线程必须等待子线程返回值才可以继续执行。有点类似于调用同步方法。上面的两种都类似于调用同步方法。

       Java内存模型:Java内存模式分为主内存和工作内存。简单来说,线程在工作时,比如执行Count++这个计算。线程先从主内存读取Count值,放入自己的工作内存,然后对工作内存的变量进行修改,修改完毕后,在写入到工作内存里。


对于线程安全和线程竞争方面,根据目前的认知,我分为两个部分:

一个是CPU资源方面,一般线程从线程池里获取,而不会单独new出一个线程。所以这回就需要考虑线程并发的数量,合理的设置线程池的线程数量就很关键了。而且针对业务场景在哪块开启多线程执行也需要仔细考量。本着提升速度,开启线程数少的原则。

一个是线程安全方面,对唯一性变量的控制,对需要操作的变量,通过synchronized关键字,Lock对象控制线程进入方法,代码块等。保证同一时刻只有一个线程去操作共享变量。对于一些公共的对象可以使用ThreadLocal变量。还有Java自带的一些原子性的包装类。


线程应用场景

个人把线程应用场景分为三个方面。

子线程之前信息同步:可以使用wait,notfiyAll等api方法。比如典型的生产者,消费者的场景。当生产者生产了物品时,调用notfiyAll方法通知唤醒其他线程。当没有物品时,消费者进入wait方法,等待状态。

主线程与子线程是同步关系:简单来说,就是主线程需要子线程的返回结构,比如对Excel的数据分析,主线程开启多个子线程对数据进行分析,但是需要子线程的分析结构,那么就可以使用线程的join方法,等待所有子线程完成。

主线程与子线程是异步关系:就是说主线程对于子线程的执行结果并不关心,这样就简单了,什么也不需要管,直接执行start方法就可以了。


猜你喜欢

转载自blog.csdn.net/wgp15732622312/article/details/80295914