Java并发编程——多线程和线程池的那些坑

最近做HBase项目有一块涉及到Java的多线程安全的问题,于是回顾了一下java多线程的东西,看了多篇多线程的写的比较好的文章之后,对这一块的知识做一个回顾总结,并附上参考文章。

第一篇会写正题,ThreadLocal的原理和用法。

目录

一、程序 & 进程 & 线程

二、多线程的使用场景

三、 多线程的优点和缺点

1. 优点

2. 缺点

四、 多线程并行 & 并发

五、线程的两种常见创建方式

1. Thread类的三种构造方法

2. 创建线程的两种常用方式

六、Thread类的11个相关方法

七、线程池

1. 为什么需要线程池

2. 线程池的创建

八、相关参考文章


一、程序 & 进程 & 线程

程序(program):为了完成特定任务,我们编写的一段代码,就是一段程序。

进程(process):是程序的一次执行过程,或者是正在运行中的一个程序。

线程(thread):一个程序内部的一个执行路径,一个进程可以包含多条线程。

通俗的理解就是:

同一时间只运行一次某一段程序,就叫进程;

同一时间多次运行一段相同的程序,就叫这段程序的进程中有多个线程。

这样多线程的优点是,同一时间可以对同一段程序,多次运行,得出不同的结果。

ps:进程中的内存,对于多线程是共享的

ps:附上一篇对这三个概念讲解的很好的文章:图文理解CPU、进程、线程

二、多线程的使用场景

1. 程序需要同时执行多个任务;

2. 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等;

3. 需要一些后台运行的程序时。

ps:每一个java程序都有一个隐含的主线程:main方法

三、 多线程的优点和缺点

1. 优点

(1)提高CPU的使用率

例如上传图片到网上,这个操作是一个进程;

单线程情况下,9张图片我们上传9次,每一次这个线程只占用CPU1%的内存;

多线程情况下,开启9条线程同时上传9张图片,上传过程中9条线程占用CPU9%的内存。

(2)提高效率

还是上面上传图片到网上的例子,单线程情况下,1张图片上传需要1秒,那9张图片就需要上传9秒;

多线程只需要1秒就能把9张图片全部上传。

(3)改善程序结构

将既长又复杂的进程,拆分成多个线程,独立运行,便于修改和理解。

2. 缺点

(1)大量线程会影响性能,因为CPU需要在它们之间切换;

(2)多线程需要更多的内存空间

(3)当多个线程同时访问一个变量对象时,可能出现线程安全问题,例如一个线程刚访问完,对象数据还没更改,下一个线程就接着访问,这样获得的数据是错误的,这就是线程安全问题

(4)多线程同时访问一个对象,可能会出现死锁问题

四、 多线程并行 & 并发

(1)并行

多个处理器或者多核处理器,同时执行多个不同的任务。

(2)并发

一个处理器,处理多个任务,多个任务通过抢占时间片的方式,同一时间只有一个线程在执行,运行完了下一个线程抢到时间片继续运行,但由于CPU的运行速度很快,所以基本上可以看做是多个线程同时运行。

五、线程的两种常见创建方式

1. Thread类的三种构造方法

(1)Thread():创建新的线程对象

(2)Thread(Runnable target):指定创建线程的目标方法,即实现了Runnable接口中的run方法

(3)Thread(Runnable target,String name):创建新的线程对象,指定创建线程的目标方法,和当前线程名称

2. 创建线程的两种常用方式

(1)实现Runnable接口,在实现类中重写Runnable接口中的run方法

(2)继承Thread类,在继承类中重写Thread类中的run方法

对比一下,实现Runnable接口的好处在于避免了单继承的局限性,并且适合多个线程共享一个接口实现类的对象,非常适合多个相同线程处理同一个共享资源。

java创建线程的三种方式及其对比

六、Thread类的11个相关方法

(1)void start():开启线程,并执行对象的run()方法

(2)run():线程的实现方法

(3)String getName():返回线程名称

(4)void setName(String name):设置线程名称

(5)static curentThread():返回当前线程

(6)static void yield():线程让步,暂停正在执行的当前线程,让步给优先级更高的线程先执行

(7)join():调用其他线程,join进来的线程优先执行完

(8)static void sleep(long millis):线程睡眠,指定时间是毫秒级

(9)stop():强制线程结束

(10)boolean isAlive():判断线程是否还活着

(11)setDaemon(true):把当前线程变成守护线程

七、线程池

1. 为什么需要线程池

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程,并且大量线程空闲,就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

这个时候,线程池的作用就出来了,

当程序需要创建大量生命周期很短暂的线程时,使用线程池可以有效控制系统中并发线程的数量,

线程池中,一个线程于空闲状态时,可以被使用,使用时变为阻塞状态,使用后又变成空闲状态,这样就可以实现线程的重复利用,这也是线程池的设计初衷。

2. 线程池的创建

在Java 5之后,可以使用工厂类Executors来创建线程池

(1)newFixedThreadPool:创建固定大小的线程池

(2)newSingleThreadExecutor:创建一个单线程的线程池

(3)newCachedThreadPool:创建带有缓存的线程池

(4)newScheduledThreadPool:创建定时和周期性执行的线程池

八、相关参考文章:

java创建线程的三种方式及其对比

带你通俗易懂的理解——线程、多线程与线程池

深入理解线程和线程池(图文详解)

线程池,这一篇或许就够了

Java并发编程:线程池的使用

猜你喜欢

转载自blog.csdn.net/wx1528159409/article/details/85275755