Java多线程基础知识整理

基础知识

进程:系统进行资源调配的一个计量单位。拥有自己被分配到的独立系统资源,这些资源足以完成工作。
线程:CPU调配的一个计量单位。隶属于某个进程之下,有自己的独立资源,但需要共享所属进程的资源才能完成工作
做个类比:
施工队(进程)接手造房子的项目(各类程序的运行),获得材料款,搅拌器,(公共资源),但是整个团队一个一个任务的完成,工作太慢,劳动力(计算能力)也会闲置,需要分成小的团队,一个人也可以是一个团队(线程),各个团队都有自己的工作计划,薪水(独立资源,东西一样,但是归自己用,共用一份工作计划那就会产生冲突,重复工作而且工作会产生错误),但是要完成整个项目的工作,必须共享包工头材料款买来的钢筋,水泥,搅拌机(进程分配的公共资源)。

多线程的目的是不让资源闲置,最核心的是CPU闲置,从而提高性能,工作效率。主要处理的问题是进程下产生了多个线程,每个线程工作时,使用公共资源或者进程调配时不产生冲突,不产生错误的数据。

容易混淆的概念:

串行:一个CPU,执行一整段逻辑,一个线程。
并行:X个CPU,各自独立执行整段逻辑中的一小段,每个CPU一个线程,共N*X个线程,但是各个线程独享各自CPU,不存在共享另外CPU资源问题。

并发:单个CPU,执行整段逻辑,但是Y个线程,通过调度算法,不停的切换CPU的使用者,由于速度很快,看起来像是同时能使用,但是在CPU层面上并不是同时进行的,Y个线程会共享资源。

线程安全与不安全:将一个大的任务分成小任务之后,每个小任务完成的时间顺序是否会对整个任务的结果有影响,简单来说,线程调度的顺序是否影响任务结果就是线程安全与否,比如多笔转账:账户1原有300元,账户1转出200,更新余额)(账户1-300,更新余额),如果在转出200元后更新余额操作前,CPU进行了切换,完成了300元的转账,并接着记账扣除200元余额为-200元,那么就转出300元也会成功,而预期的结果是第一笔200元转出成功,余额100元,第二笔转出不成功。

线程同步:人为的加上限制,让线程不安全的逻辑变成线程安全。如上面的转账,人为的限制操作操作共享资源(账户余额)必须完成整个逻辑,不会中途终端,这样就变成线程安全了。具体操作是加上@synchronized关键字。

线程状态:
new:新建完成的状态,还没有执行代码。
runnable:
(1)当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,完成之后线程就处于就绪状态。处于就绪状态的线程并不一定立即运行run()方法,要同其他线程竞争CPU的使用权,只有得到了CPU的使用权才运行run()中的代码。
(2)主动(yield)或者被动(时间片跑完了)的让出CPU的使用权。
running:得到CPU的使用权,调用run()。
blocked:阻塞状态。可能以下几种情况引起:
(1)调用sleep(),时间结束后进入runnable状态。
(2)需要使用到I/O资源,但正在被别的线程使用,进入阻塞状态,获得I/O的使用权时,进入runnable状态。
(3)试图得到一个锁,但是该锁正在被别的线程持有,则进入阻塞状态,当获取锁之后,进入runnable状态。
(4)等待某个条件的触发,当被触发之后,进入runnable状态。
(5)调用join方法,相当于把自己CPU的时间片让给其他线程使用,使用期间被阻塞,是用完成之后进入runnable状态。
(6)调用wait方法,需要被notify()/notifyAll()方法,才能到达runnable方法,否则会放到等待池。
dead:结束状态。1,运行完run方法正常结束2,遇到未捕获异常被迫退出。

在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。

多线程中的内存:主存heap(共享),线程栈stack(每个线程有只属于自己的)。
线程先从heap中获取需要的数据load到stack,完成之后再save回去。
volatile:主要作用是针对每次对变量的操作都触发一次load and save操作。换个说法就是,多线程每个线程会缓存变量的值,但是操作之后没有立即更新heap中的值,就出现其它线程获取的是这个变量没有改变后前的值,实际上是需要获取操作后更新的值,而volatile就强制要求不缓存,也就不会存在不一致的问题。同时也可以看出,线程安全的情况下,volatile关键字会牺牲性能。

线程的三种创建方法:
1.extends Thread,重写run方法,启动的时候调用start方法。
2.实现runnable接口,重写run方法。然后作为Thread的参数,新建线程。
3.线程池的使用。

JAVA多线程API,java.until.concurrent的学习整理
BlockingQueue:
Java多线程基础知识整理_第1张图片ArrayBlockingQueue:
由Array做底层实现,所以有界,并且无法改变。
内部采用FIFO策略,头肯定是存储时间最久的,同理,尾是时间最短的。
DelayQueue:
对元素的持有一个特定的时间,注入的元素必须实现java.util.concurrent.Delayed接口
LinkedBlockingQueue:
底层以链式结构实现,没有上线,或则可以制定上限,同样是FIFO策略。
PriorityBlockingQueue:
所有插入的元素必须实现comparable接口,意味这些元素本身有能比较的属性,也就决定了优先级。
SynchronousBlockingQueue:
内部职最多只能存放一个元素,如果再存放另外的元素则则会阻塞直到之前的元素被取出,如果为空时去取出元素,也阻塞直到有元素被放入。
BlcokingDeque:
阻塞双端队列,Deque是Double Ended Queue的缩写,因此,双端队列是一个你可以从任意一端插入或者抽取元素的队列。
LinkedVBlockingDeque:
链式结构实现的BlockingDeque。会涉及到两端的操作,也就是在Queue的基础上指明了是first还是last。
ConcurrentHashMap:
 在你向其中写入对象的时候,ConcurrentHashMap 也不会锁住整个 Map。它的内部只是把 Map 中正在被写入的部分进行锁定。CountDownLatch: 以一个给定的初始量进行初始化,他允许一个或者多个线程等待一系列的操作完成。 


你可能感兴趣的:(基础知识)