线程笔记
这一阵读了《JAVA并发编程实战》,写demo,看资料,记了一堆乱七八糟的东西。记下笔记,有空看看,免得遗忘
线程状态
状态 | 简易说明 | 进入方法 | 备注 |
---|---|---|---|
新建状态(New) | 刚刚创建,没开始执行 | 对象new之后 | |
就绪状态(Runnable) | 已经准备好,随时可以调用 | thread.start()之后,线程线程执行之前New 或者,阻塞接触之后 |
|
运行状态(Running) | 执行中 | 就绪的线程获取CPU运行权限 | 只能【就绪】->【运行】 |
阻塞状态(Blocked) | 放弃CPU执行 | wait()(等待)、synchronized锁(同步)、sleep或join()(切换)之后 | IO也会造成阻塞(read(),write()) |
死亡状态(Dead) | 执行完毕或者异常退出 |
参考:http://www.cnblogs.com/skywang12345/p/3479024.html
线程状态改变方法
名称 | 简易说明 | 备注 |
---|---|---|
wait() | 线程等待,线程进入等待阻塞状态,等待到时间或者被唤醒 | 1,t1.wait()不是使t1等待,可是执行此语句的线程等待 2,会释放所有同步锁 |
notify()和notifyAll() | 线程唤醒,唤醒单个/全部的等待线程 | t1.不是唤醒自身,而是等待中的线程 |
yield() | 线程让步,线程重新进入就绪状态 | 不会释放锁 |
sleep() | 限时阻塞,进入阻塞一定时间后,自动进入就绪状态 | 不会释放锁 |
join() | t1.join(),让当前线程阻塞,直到t1线程执行完成后,进入就绪状态 | 本质是主线程不断wait() |
interrupt() | 线程中断,设置线程的中断标志,线程执行到阻塞时,清除标记并抛出InterruptedException的异常 | 1,当前线程以外使用interrupt(),会检测权限 |
注:由于notify(), wait()依赖于对象自身的同步锁,所以这些方法存在于Object对象中
加锁方法
名称 | 简易说明 | 用法 | 备注 |
---|---|---|---|
synchronized | 同步方法或代码块 | synchronized 方法(){ ... } synchronized(锁对象){ ... } |
依赖于对象:不明确锁对象时,锁对象是类的实例自身 |
volatile | 修饰变量,保证每次直接读值 | volatile 变量类型 变量 | 常用于flg用的共享成员的 |
Lock | 显示的加锁方法 | Lock lock = new ReentrantLock(); ...... try { lock.lock(); ..... } finally { lock.unlock(); } |
显式的创建,有tryLock()等方法扩展 ReentrantLock:独占锁,公平锁。 ReadWriteLock:读写锁:读取锁是共享锁,写入锁是独占锁。 |
CountDownLatch | 闭锁:计数,阻塞等待至计数为零 | new CountDownLatch(int 等待数) | countDown():计数减少 await():阻塞等待值计数为零 |
CyclicBarrier | 栅栏:阻塞的线程达到一定数量之后,一起执行 | new CyclicBarrier(int 等待数) | await():阻塞等待,直到阻塞的线程达到一定数量 |
Semaphore | 信号量:有N个资源,如获取时无资源则阻塞等待 | new Semaphore(int 初始资源数) | relase():释放/增加资源 acquire():获取,减少资源 |
线程内任务载体(全是接口):
接口名 | 父类 | 简易说明 | 方法 |
---|---|---|---|
Runnable | 无 | 最基本的线程载体 | void run()包含执行内容,无参数返回值 |
TimerTask | Runnable | Timer用定时的线程 | void run()包含执行内容,无参数返回值 boolean cancel()自身取消用 |
Callable | 无 | 带返回值得线程载体 | V call()包含执行内容,并返回返回值 |
线程载体:
类名/接口名 | 载体类型 | 简易说明 | 创建 | 方法 |
---|---|---|---|---|
Thread(类) | Runnable | 线程(Runnable的实现) | new Thread(Runnable target) | void start()启动线程 String getName()返回该线程的名称 void setName(String name)设置线程名称 int getPriority()返回线程的优先级。 void setPriority(int newPriority)更改线程的优先级 boolean isDaemon()该线程是否为守护线程 void setDaemon(boolean on)将该线程标记为守护线程或用户线程 void sleep(long millis) 线程休眠 void interrupt()中断线程 void yield()线程让步,切换线程 void join()使得调用线程等待,直到此该线程终止 |
Timer(类) | TimerTask(Runnable子类) | 多线程,定时/延时启动 | new Timer() | void schedule(TimerTask task, long delay, long period)追加并启动线程(按照上次的结束时间循环) scheduleAtFixedRate(TimerTask task, long delay, long period)追加并启动线程(按照上次的开始时间循环) void cancel()线程取消 int purge()移除所有已取消的任务 |
Executor(接口) | Runnable | 多线程线程池 | Executors.newFixedThreadPool(int num)限制线程数的线程池 Executors.newCachedThreadPool()可缓存线程池 Executors.newScheduledThreadPool(int num)定长线程池,类似timer Executors.newSingleThreadExecutor()单线程线程池,唯一执行 |
void execute(Runnable command)追加执行线程 |
ExecutorService(接口) | Runnable Callable |
多线程线程池管理(Executor的扩展) | 同上 | Future Future<?> submit(Runnable task)提交Runnable线程 List<Future void shutdown()关闭 |
Future(接口) | 承载线程状态 | 线程的状态管理对象 | 使用ExecutorService的相关方法的返回值 | V get()取得执行结果,线程未执行完毕时,阻塞 V get(long timeout, TimeUnit unit)限时取得结果,超时抛异常 boolean cancel(boolean mayInterruptIfRunning)取消线程 boolean isCancelled()判断是否取消 boolean isDone()判断是否执行完成 |
FutureTask(类) | Future + Runnable或Callable | 线程和其管理对象的结合体 | FutureTask(Callable FutureTask(Runnable runnable, V result) |
用时有线程和future的方法 |
CompletionService(接口) | Executor | 队列的方式管理多线程 | new ExecutorCompletionService(Executor executor) ExecutorCompletionService是其接口的实现 |
Future Future Future Future Future |
注:对于Thread的start()和run():
start():它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
run():run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!
也就是说start()是启动线程,在新线程执行run()的内容;run()是执行名为run()的方法
线程池的实现:
- 线程池的实现是ThreadPoolExecutor(->AbstractExecutorService->ExecutorService->Executor)。
- Executors.newXXX等方法,实际上都是new ThreadPoolExecutor。(java8新增的newWorkStealingPool使用另一种实现ForkJoinPool,可拆分大任务)
- ThreadPoolExecutor的初始化参数如下:
名称 | 类型 | 说明 | 备注 |
---|---|---|---|
corePoolSize | int | 基本大小 | 不推荐设0不要太小 |
maximumPoolSize | int | 最大大小 | 不要太大 |
keepAliveTime | long | 超时时间 | 当将allowCoreThreadTimeOut设置为true时对corePoolSize生效 |
unit | TimeUnit | keepAliveTime的单位 | 如TimeUnit.SECONDS |
workQueue | BlockingQueue |
任务队列 | 一般使用LinkedBlockingQueue或者SynchronousQueue |
threadFactory | ThreadFactory | 线程工厂 | 提供创建新线程的功能 |
handler | RejectedExecutionHandler | 拒绝策略(饱和策略) | 线程池满时的处理方法: AbortPolicy DiscardPolicy DiscardOldestPolicy CallerRunsPolicy |
线程锁:
名词 | 简易说明 | 例子 | 备注 |
---|---|---|---|
死锁 | 自己占有他人请求资源的时候,去请求他人的资源 | ①程序1,锁住资源A ②程序2,锁住资源B ③程序1,请求资源B,阻塞 ④程序2,请求资源A,阻塞 |
相互出在阻塞状态,简单可记为A->B,B->A |
活锁 | 执行状态和顺序一定的情况下,一旦一次失败,导致程序不断重试 | ①程序1,锁住资源A ②程序2,锁住资源B ③程序1,请求资源B,请求失败 ④程序2,请求资源A,请求失败 ⑤程序1,释放资源A,重新开始 ⑥程序2,释放资源B,重新开始 之后从①开始,循环 |
不阻塞,不断执行,不断失败重试 |
饥饿 | 由于不公平锁,优先级等问题,导致一直无法取到资源 | ①程序1,程序2争夺资源资源A,程序2胜出 ②程序1,程序3争夺资源资源A,程序3胜出 ③程序1,程序4争夺资源资源A,程序4胜出 ... |
不阻塞,不重复,但某些程序无法执行 |