配色: 字号:
多线程概述
2021-01-03 | 阅:  转:  |  分享 
  
202X多线程&并发2021-01-03演讲人目录基础部分01.高级部分02.基础部分01基础部分0601对象及变量的并发访问实现方
式0502线程的分类启动0403线程的优先级常用API基础部分线程间通信Lock的使用定时器单例模式&多线程基础部分实现方
式继承自thread,实现run方法实现runnable接口,实现run方法基础部分启动调用start方法线程的启动具有随机性12
基础部分常用APIABCcurrentThread()isAlive()sleep()DEFgetId()停止线程暂停/恢复线程基
础部分常用APIyield()currentThread()获得当前线程,如果在main中调用,当前线程是main而不是被star
t的线程isAlive()判断当前线程是否处于活动状态线程处于正在运行或准备开始运行的状态,就认为线程是
“存活”的。sleep()方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休
眠(暂停执行)。这个“正在执行的线程”是指this.currentThread()返回的线程。getId
()getId()方法的作用是取得线程的唯一标识。停止线程使用退出标志,使线程正常退出,也就是当
run方法完成后线程终止。停止线程stop()这个方法是不安全的(unsafe),而且是已被弃用
作废的(deprecated)9,300Million单击此处添加标题单击此处输入你的正文,文字是您思想的提炼,为了最终演示
发布的良好效果,请尽量言简意赅的阐述观点;根据需要可酌情增减文字,以便观者可以准确理解您所传达的信息。调用stop()方法时
会抛出java.lang.ThreadDeath异常,但在通常的情况下,此异常不需要显式地捕捉。使
用interrupt()方法中断线程。调用interrupt()方法仅仅是在当前线程中打了一个停止的
标记,并不是真的停止线程。interrupt()测试当前线程是否已经中断。线程的中断状态由该方
法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除
了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。isInter
rupt()测试线程Thread对象是否已经是中断状态,但不清除状态标志。停止线程抛出Interrupt
edExceptionif(this.interrupted()){?System.out.println(\"已经
是停止状态了!我要退出了!\");thrownewInterruptedException();?}停止线程使用
return停止线程建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将
异常向上抛,使线程停止的事件得以传播。suspend()废弃的方法缺点此方法是独占的,如果拿到锁并且调用了线程的
suspend()方法,那其他线程就再也拿不到锁,无法执行了容易出现因为线程的暂停而导致数据不同步的情况。
暂停/恢复线程resume()yield()放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时
间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。基础部分线程的优先级setPriori
ty()特性setPriority()线程的优先级分为1~10这10个等级,如果小于1或大于10,
则JDK抛出异常thrownewIllegalArgumentException()。JDK中使用3个常量
来预置定义优先级的值,publicfinalstaticintMIN_PRIORITY=1;public
finalstaticintNORM_PRIORITY=5;publicfinalstaticintMAX_
PRIORITY=10;特性继承特性规律性:高优先级的线程总是先执行完随机性:高优先级的线程不一定每一次都先执行完基础部分
线程的分类用户线程守护线程守护线程守护线程是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动
销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。但是在主线程中调用守
护线程.join(),那就守护不了了基础部分对象及变量的并发访问volatilesynchronized同步方法synchroni
zed同步语句块synchronized同步方法方法内的变量为线程安全实例变量非线程安全两个线程访问同一个对象中的同步方法时一定
是线程安全的java中的锁是对象锁:如果拿到锁,则其他线程是不能调用对象中的所有synchronized方法的synchroniz
ed拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的
锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
出现异常,锁自动释放synchronized同步方法同步不具有继承性synchronized同步语句块同步方法的弊端,方法中不需要
同步的代码也做了同步,增加了方法的执行时间synchronized同步语句块并发线程访问同一个对象object中的synchron
ized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
synchronized同步语句块不在synchronized块中就是异步执行,在synchronized块中就是同步执行。sy
nchronized同步语句块当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个o
bject中所有其他synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的“对象监视器
”是一个。多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,
调用的效果就是按顺序执行,也就是同步的,阻塞的。synchronized同步方法synchronized(this)同步代码块
锁非this对象同步代码块放在非同步synchronized方法中进行声明,并不能保证调用方法的线程的执行同步/顺序性,也就是
线程调用方法的顺序是无序的,虽然在同步块中执行的顺序是同步的,这样极易出现“脏读”问题。所得几种类型多个线程调用同一个对象中的不
同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的
,阻塞的。synchronized同步方法对其他synchronized同步方法或synchronized(this)同步代码
块调用呈阻塞状态。同一时间只有一个线程可以执行synchronized同步方法中的代码。多个线程调用同一个对象中的不同名称的sy
nchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。
synchronized(this)同步代码块对其他synchronized同步方法或synchronized(this)同步代
码块调用呈阻塞状态。同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码。多个线程调用同一个对象中
的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同
步的,阻塞的。锁非this对象如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响运
行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁
this同步方法争抢this锁,则可大大提高运行效率。使用“synchronized(非this对象x)同步代码块”格式进行同步
操作时,对象监视器必须是同一个对象。如果不是同一个对象监视器,运行的结果就是异步调用了,就会交叉运行。多个线程调用同一个对象中的不
同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的
,阻塞的。所得几种类型对象锁Class锁synchronized同步语句块死锁JAVA_HOME下执行jps列出java进程
执行jstack进程idvolatile关键字volatile的主要作用是使变量在多个线程间可见。volatile的作用是强制从
公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。类的成员变量存在于公共堆栈及线程的私有堆栈中。在JVM被设置为-se
rver模式时为了线程运行的效率,线程一直在私有堆栈中取值线程的私有堆栈读取公共内存关键字volatile虽然增加了实例变量在多
个线程之间的可见性,但它却不具备同步性,那么也就不具备原子性。volatile变量在内存中的工作过程使用原子类进行i++操作sy
nchronized代码块有volatile同步的功能volatile使用原子类进行i++操作AtomicInteger等待/通
知join基础部分线程间通信InheritableThreadLocalThreadLocalwait()方法wait()的作用
是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程置入“预执行队列”中,并且在wait(
)所在的代码行处停止执行,直到接到通知或被中断为wait()方法被执行后,锁立即释放线程呈wait()状态时,调用线程对象的i
nterrupt()方法会出现InterruptedException异常。wait()wait(1000),等待1s,超过1s
自动唤醒当多个执行相同任务的线程,条件判断wait()的时候要用while而不能用if当线程wait之后,又被唤醒的时候,是
从wait后面开始执行,而不是又从头开始执行的,所以如果用if的话,被唤醒之后就不会在判断if中的条件,而是继续往下执行了等待/通
知notify()notify()也要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁。如果调用notify
()时没有持有适当的锁,也会抛出IllegalMonitorStateException。该方法用来通知那些可能等待该对象的对象锁
的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程对其发出通知notify,并使它等待获取该对象
的对象锁。需要说明的是,在执行notify()方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,
要等到执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态
所在的线程才可以获取该对象锁。notify()方法执行后,不自动释放,必须执行完notify()方法所在的同步synchroniz
ed代码块后才释放锁。等待/通知notify()notifyAll()唤醒所有线程等待/通知线程状态切换图两个队列就绪队列存储将
要获得锁的线程被notify()并且拿到锁的线程阻塞队列存储被阻塞的线程调用wait()的线程不同线程间直接传送数据字节流P
ipedInputStreamPipedOutputStream字符流PipedReaderPipedWriterjoinjo
in(long)中的参数是设定等待的时间thread.join()作用:创建子线程的主线程,必须等待子线程执行完毕,或销毁后后,才
能够提前执行完成方法join(long)的功能在内部是使用wait(long)方法来实现的,所以join(long)方法具有释
放锁的特点。ThreadLocal作用:解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒
子中可以存储每个线程的私有数据。ThreadLocalThreadLocalthreadLocal=newThreadL
ocal();ThreadLocal解决threadLocal初始化get()为null的问题继承自ThreadLocal类,
复写initialValue()方法InheritableThreadLocal以在子线程中取得父线程继承下来的值。基础部分Lo
ck的使用ReentrantLockReentrantReadWriteLock相关APIReentrantLock调用Reent
rantLock对象的lock()方法获取锁,调用unlock()方法释放锁。ReentrantLocklock=newR
eentrantLock();lock.lock();ReentrantLock01020403lock.unlock();//d
osomethingelse.基本用法ConditionCondition类是在JDK5中出现的技术,使用它有更好的灵活性,比
如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的C
Conditioncondition=lock.newCondition();condition.wait()Obje
ct类中的wait()方法相当于Condition类中的await()方法。Object类中的wait(longtimeout)方
法相当于Condition类中的await(longtime,TimeUnitunit)方法。Conditioncondition
.signal()Object类中的notify()方法相当于Condition类中的signal()方法。Object类中的n
otifyAll()方法相当于Condition类中的signalAll()方法。ReentrantLock公平锁和非公平锁2公平
锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。非公平锁就是一种获取锁的抢占机制,是随机获得
锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了。newReentra
ntLock(isFair)共享锁关系读操作相关的锁读锁之间不互斥读锁与写锁互斥使用ReentrantReadWriteLoc
klock=newReentrantReadWriteLock();lock.readLock().lock();//d
osomethingelse.lock.readLock().unlock();排它锁关系写操作相关的锁写锁与写锁互斥使用
ReentrantReadWriteLocklock=newReentrantReadWriteLock();lock.w
riteLock().lock();//dosomethingelse.lock.writeLock().unlock();
ACEBDF相关APIlock.getHoldCount()lock.getWaitQueueLength(condition)l
ock.hasQueuedThreads()lock.hasQueuedThread(thread)lock.getQueueLe
ngth()lock.hasWaiters(condition)相关APIlock.isFair()lock.isHeldByCu
rrentThread()lock.isLocked()lock.lockInterruptibly()lock.tryLock(
)lock.tryLock(longtimeout,TimeUnitunit)相关APIlock.getHoldCount(
)查询当前线程报错此锁定的个数,也就是调用lock()的次数相关APIlock.getQueueLength()返回正等待获取此锁
定的线程估计数,比如有5个线程,1个线程首先执行await()方法,那么在调用getQueueLength()方法后返回值是4,说
明有4个线程同时在等待lock的释放。相关APIlock.getWaitQueueLength(condition)返回等待与此锁
定相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,
则调用getWaitQueueLength(Conditioncondition)方法时返回的int值是5。相关APIlock.h
asQueuedThread(thread)查询指定的线程是否正在等待获取此锁定相关APIlock.hasQueuedThread
s()查询是否有线程正在等待此锁定相关APIlock.hasWaiters(condition)是查询是否有线程正在等待与此锁定有
关的condition条件相关APIlock.isHeldByCurrentThread()查询当前线程是否保持此锁定相关APIl
ock.isLocked()查询此锁定是否由任意线程保持相关APIlock.lockInterruptibly()如果当前线程未被
中断,则获取锁定,如果已经被中断则出现异常相关APIlock.tryLock()仅在调用时锁定未被另一个线程保持的情况下,才获取该
锁定相关APIlock.tryLock(longtimeout,TimeUnitunit)方法booleantryLoc
k(longtimeout,TimeUnitunit)的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,
则获取该锁定基础部分定时器TimerTimerTaskTimerTimerTask是以队列的方式一个一个被顺序执行的,所以执行的时
间有可能和预期的时间不一致,因为前面的任务有可能消耗的时间较长,则后面的任务运行的时间也会被延迟。如果执行任务的时间早于当前时间
,则立即执行task任务。cancel作用是将任务队列中的全部任务清空。Timer类中的cancel()方法有时并不一定会停止
执行计划任务,而是正常执行。有时并没有争抢到queue锁,所以TimerTask类中的任务继续正常执行。几种用法schedule(
TimerTasktask,Datetime)在指定的日期执行一次某一任务。schedule(TimerTasktask
,DatefirstTime,longperiod)是在指定的日期之后,按指定的间隔周期性地无限循环地执行某一任务。sched
ule(TimerTasktask,longdelay)以当前的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次T
imerTask任务。schedule(TimerTasktask,longdelay,longperiod)当前的时
间为参考时间,在此时间基础上延迟指定的毫秒数,再以某一间隔时间无限次数地执行某一任务。scheduleAtFixedRate(
TimerTasktask,DatefirstTime,longperiod)TimerTaskcancel将自身从任
务队列中清除。其他任务不受影响。TimerTask凡是使用方法中带有period参数的,都是无限循环执行TimerTask中的任务
。基础部分单例模式&多线程饱汉模式饿汉模式饱汉模式不存在线程安全问题饿汉模式存在线程安全问题解决:加锁,加同步块但是效率低
应该只针对需要同步的代码部分加锁所以引入DLC双重锁定机制高级部分02高级部分0102CompletionServiceCou
ntDownLatch&CyclicBarrier0304Semaphore&Exchanger并发集合框架050
6Future&CallableExecutor高级部分Phaser高级部分CompletionServiceABC
D作用实现类方法总结作用实现类12是以异步的方式一边生产新的任务,一边处理已完成任务的结果,这样可
以将执行任务与处理任务分离开来进行处理。使用submit执行任务,使用take取得已完成的任务
,并按照完成这些任务的时间顺序处理它们的结果。ExecutorCompletionServiceCom
pletionServiceCompletionService方法方法take()取得最先完成任务的Future
对象,谁执行时间最短谁最先返回。方法poll()的作用是获取并移除表示下一个已完成任务的
Future,如果不存在这样的任务,则返回null,方法poll()无阻塞的效果。方法Futur
e<V>poll(longtimeout,TimeUnitunit)的作用是等待指定的tim
eout时间,在timeout时间之内获取到值时立即向下继续执行,如果超时也立即向下执行。
CompletionService总结接口CompletionService完全可以避免FutureTask类阻塞
的缺点,可更加有效地处理Future的返回值,也就是哪个任务先执行完,CompletionServ
ice就先取得这个任务的返回值再处理。高级部分CountDownLatch&CyclicBarrier
CountDownLatchCyclicBarrier12CountDownLatch作用基本用法其他概念我的理解Count
DownLatch作用门闩,也就是有“门锁”的功能,所以当门没有打开时,N个人是不能进入屋内
的,也就是N个线程是不能继续向下运行的,支持这样的特性可以控制线程执行任务的时机,使线
程以“组团”的方式一起执行任务。类CountDownLatch所提供的功能是判断count计数不
为0时则当前线程呈wait状态,也就是在屏障处等待CountDownLatch基本用法定一个计数
,当使用这个CountDownLatch类的线程判断计数不为0时,则呈wait状态,如果为0
时则继续运行。实现等待与继续运行的效果分别需要使用await()和countDown()方法
来进行。调用await()方法时判断计数是否为0,如果不为0则呈等待状态。其他线程可以调
用count-Down()方法将计数减1,当计数减到为0时,呈等待的线程继续运行。而方法
getCount()就是获得当前的计数个数。CountDownLatch基本用法代码newCountDown
Latch(1)的作用是创建1个计数的CountDownLatch类的对象,当线程执行down.
await()代码时呈等待状态,程序不向下继续运行。程序执行down.countDown()代码
时计数由1变成0,以前呈等待状态的线程继续向下运行。CountDownLatch其他概念方法aw
ait(longtimeout,TimeUnitunit)的作用使线程在指定的最大时间单位内进入
WAITING状态,如果超过这个时间则自动唤醒,程序继续向下运行。参数timeout是等待的时
间,而unit参数是时间的单位。方法getCount()获取当前计数的值。CountDownLatc
h我的理解门上一共有10把锁,10个人有10把钥匙,当锁全部打开,10个人才可以进入下一步操作调用countdownlatch.a
wati的线程处于阻塞状态,当countdownlatch调用countdownf方法将count计数减为0的时候,await的线
程从阻塞状态变为可运行状态CyclicBarrier作用基本用法其他概念CyclicBarrier作用类CyclicBar
rier不仅有CountDownLatch所具有的功能,还可以实现屏障等待的功能,也就是阶段性同步
,它在使用上的意义在于可以循环地实现线程要一起做任务的目标,而不是像类CountDow
nLatch一样,仅仅支持一次线程与同步点阻塞的特性,CyclicBarrier作用它允许一组线程
互相等待,直到到达某个公共屏障这些线程必须实时地互相等待,这种情况下就可以使用CyclicBarr
ier类来方便地实现这样的功能。CyclicBarrier类的公共屏障点可以重用,所以类的
名称中有“cyclic循环”的单词。CyclicBarrier作用CountDownLatch类的使用情况
是两个角色之间互相等待,而Cyclic-Barrier的使用情况是同类互相等待。和CountDo
wnLatch类不同,类CyclicBarrier的计数是加法操作。CyclicBarrier作用类Cyc
licBarrier具有屏障重置性,这句话的意思就是如果全部线程await的个数都到达了屏障数,那屏障就会被重置为0,然后
在从0开始累加到屏障数CyclicBarrier基本用法一组线程中每个线程调用CyclicBarrier.awati()方法等待
其他线程到达一个公共屏障点newCyclicBarrier(5,Runnable),设置最大为5个的parties
同行者,也就是5个线程都执行了cbRef对象的await()方法后程序才可以继续向下运行,
否则这些线程彼此互相等待,一直呈阻塞状态。CyclicBarrier其他概念getNumberWaitin
g(),该方法的作用是获得有几个线程已经到达屏障点。CyclicBarrier其他概念方法isBr
oken()查询此屏障是否处于损坏状态。CyclicBarrier其他概念方法isBroken()查询此
屏障是否处于损坏状态。由于中断或者超时提前离开了屏障点,其他所有在屏障点等待的线程也会
抛出BrokenBarrierException或者InterruptedException异常,并且离开屏障点。
CyclicBarrier其他概念方法await(longtimeout,TimeUnitunit)的功能是
如果在指定的时间内达到parties的数量,则程序继续向下运行,否则如果出现超时,则抛出
TimeoutException异常。CyclicBarrier其他概念方法getParties()的作用是取得
parties个数。CyclicBarrier其他概念reset()的作用是重置屏障。0201高级部分Semaph
ore&ExchangerExchangerSemaphoreSemaphore作用主要用法其他概念Semaphore作用
控制线程并发的数量Semaphore主要用法semaphore.acquire();System.out.
println(Thread.currentThread().getName()+\",begintimer=\"+Sy
stem.currentTimeMillis());Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+\",endtime
r=\"+System.currentTimeMillis());semaphore.release();
Semaphore其他概念有参方法acquire(intpermits)的功能是每调用1次此方法,就使用
x个许可。说白了就是一共有10把锁,没进来一个人就消耗掉2把锁,所以一共只能进来5次Semaphore其他概念构造参数
newSemaphore(5);中的5并不是最终的许可数量,仅仅是初始的状态值。比如初始是5,如果release
(5),那avaliablePermits=10Semaphore其他概念方法acquireUninterruptibly()
的作用是使等待进入acquire()方法的线程,不允许被中断。也就是正常执行不抛出异常Semaphore
其他概念availablePermits()返回此Semaphore对象中当前可用的许可数,此方法通常用
于调试,因为许可的数量有可能实时在改变,并不是固定的数量。Semaphore其他概念drainPer
mits()可获取并返回立即可用的所有许可个数,并且将可用许可置0。Semaphore其他概念方法getQueueLength()的作用是取得等待许可的线程个数。Semaphore其他概念方法hasQueuedThreads()的作用是判断有没有线程在等待这个许可。Semaphore其他概念Semaphoresemaphore=newSemaphore(1,isFair);获得许可的顺序与线程启动的顺序有关,这时信号量就要分为公平与非公平的。所谓的公平信号量是获得锁的顺序与线程启动的顺序有关,但不代表100%地获得信号量,仅仅是在概率上能得到保证。而非公平信号量就是无关的了。Semaphore其他概念无参方法tryAcquire()的作用是尝试地获得1个许可,如果获取不到则返回false,此方法通常与if语句结合使用,其具有无阻塞的特点。无阻塞的特点可以使线程不至于在同步处一直持续等待的状态,如果if语句判断不成立则线程会继续走else语句,Semaphore其他概念有参方法tryAcquire(intpermits)的作用是尝试地获得x个许可,如果获取不到则返回false。Semaphore其他概念有参方法tryAcquire(intlongtimeout,TimeUnitunit)的作用是在指定的时间内尝试地获得1个许可,如果获取不到则返回false。Semaphore其他概念有参方法tryAcquire(intpermits,longtimeout,TimeUnitunit)的作用是在指定的时间内尝试地获得x个许可,如果获取不到则返回false。Semaphore&ExchangerExchanger010203作用基本用法其他概念感谢聆听
献花(0)
+1
(本文系职场细细品原创)