实现多线程的方法
extends Thread
implement Runnable
new Runnable(){} 不是实例化Runnable接口,是一种内部类的简写。
run()和start()的区别
run()方法只是类的一个普通方法。如果直接调用run()方法,程序中依然只有主程序这一线程,其程序执行路径只有一条,还是要顺序执行。
等run()方法执行完毕后才可以继续执行下面的代码。
start方法,真正实现多线程,通过调用Thread类的start方法来启动一个线程,这时线程处于就绪(可运行)状态,并没有运行,得到cpu时间片后,就开始执行run()。
注意:得到cpu时间片后不需要等待run()方法执行完毕,即可继续执行下面的代码。所以run()方法并没有实现多线程。
Thread类
- Thread.yield()方法的作用:暂停当前正在执行的线程对象,并执行其它相同优先级线程。yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行态转到可运行态。
- Thread.sleep()方法(休眠)是线程类Thread的静态方法,调用此方法让当前线程暂停执行指定的时间,将执行机会让给其它线程,但是线程锁依然保持,因此休眠时间结束后会自动恢复。
Thread.sleep()和Object.wait都可以抛出InterruptedException,且该异常为检查异常,不能忽略。
- Object.wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有待用notify()或者notifyAll()才能唤醒等待池中的线程进入等锁池,如果线程重新获得对象的锁就可以进入就绪状态。
- Thread.join()
join()被打断会导致interruptedException异常。
Thread.join()把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B调用了线程A中的join方法,直到线程A执行完毕后,才会继续执行线程B
Daemon线程
setDaemon()设置必须要在start()之前,当线程正在运行时调用会产生异常。
Thread Local类
- 采用哈希表的方式来为每个线程提供一个变量的副本;
- 保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏。
线程安全类
HashTable
、Vector
、Stack
、enumeration
、StringBuffer
、Properties
、concurrentHashMap
线程中断或停止运行的情况
- InterruptedException异常被捕获
- 线程调用wait()方法,强行打断当前操作,进入阻塞状态,需要用notify()或notifyAll()方法才能进入就绪状态。
CyclicBarrier屏障类
await()方法可以简单理解为:等待多个线程同事到达之后才能继续进行,在此之前它是这些线程的屏障,线程不能继续进行。对于失败的同步尝试,CyclicBarrier使用一种要么全部要么全不(all-or-none)的破坏模式:如果因为中断、超时或失败等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其它线程也将通过BrokenBarrierException
(如果它们几乎同时被中断,则用interruptedExcption
)以反常的方式离开。
线程局部存储TLS(thread local storage)
- 解决多线程中的对同一变量访问冲突的一种技术。
- TLS会为每一个线程维护一个和该线程绑定的变量副本。
- Java平台的java.lang.ThreadLocal是TLS技术的一种实现
关键字
volatile
多线程访问volatile不会发生阻塞。
volatile保证数据的可见性
,有序性
,但不能保证原子性。
volatile解决变量在多线程之间的可见性。
不能保证线程安全。
synchronized
锁定当前变量(互斥锁),只有当前线程可以访问该变量。
多线程访问synchronized会出现阻塞。
synchronized保证数据的可见性
,有序性
,原子性
。
synchronized解决多线程之间资源同步问题。