目录java
一、多线程基础编程
1.2 建立线程网络
1.3 线程的生命周期多线程
线程是操做系统可以进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运做单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每一个线程执行不一样的任务。
特色:轻型实体、独立调度和分派的基本单位、可并发执行、共享进程资源
建立线程的两种方法:1 实现Runnable接口并从写run方法;2 集成Thread类并从新run方法。
实现Runnable接口:
集成Thread类:
线程的什么周期大体能够分为五个阶段:一、new(新建) 二、Runnable(就绪) 三、Running(运行) 四、Blocked(阻塞) 五、Terminated(结束)
当咱们使用关键字new建立一个Thread对象时,此时他并不处于执行状态,由于没有调用start的方法启动该线程,那么线程的状态为New状态。NEW状态只有经过start方法进入RUNNABLE(就绪状态)状态。
线程对象进入RUNNABLE(就绪状态)必须调用start方法,那么此时才真正的在JVM进程中建立了一个线程,线程的运行与否都要由CPU的调度,那么咱们把这个中间转态成为可执行状态,就是已经就绪,可是没有真正的执行起来。
一旦CPU经过轮询或者其余方式从任务可执行队列中选中了线程,那么此时他才能真正的执行本身的逻辑代码。在该状态下,线程能够发生以下状态切换:
1)直接进入TERMINATED状态,好比调用了JDK已经不推荐使用的stop方法或者判断某个逻辑标识。
2)进入BLOCKED状态,好比调用sleep,或者wait方法进入waitSet中
3)进入某个阻塞的IO操做,好比因网络数据的读写进入了BLOCKED状态
4)获取某个锁资源,从而加入到该锁的阻塞队列中而进入BLOCKED状态
5)因为CPU的调度器轮询是该线程放弃执行,进入RUNNABLE状态
5)线程主动yield(线程让步)方法,放弃CPU执行权,进入RUNNABLE状态
就是由1.3.3线程的RUNNING状态进入BLOCKED状态
在该状态下,线程能够发生以下状态切换:
1)直接进入TERMINATED状态,好比调用了JDK已经不推荐使用的stop方法或者判断某个逻辑标识。
2)线程阻塞的操做结束,进入到RUNNABLE状态
3)线程完成休眠,进入RUNNABLE状态
4)wait中的线程被其余线程的notify/notifyall唤醒,进入RANNABLE状态
线程的TERMINATED状态是一个线程的最终状态,该状态不会再切换到任何状态,进入此状态就意味着该线程的整个生命周期都结束了。
程序以下:
什么是守护线程:
JVM在没有一个非守护线程运行时,JVM将会退出。守护线程拥有本身结束本身生命周期的特性,而非守护线程没有。JVM的垃圾回收线程就是典型的守护线程,在垃圾回收结束后自动结束生命周期。
sleep是一个静态方法,其有两个重载方法,起重一个须要传入毫秒数,另外一个既须要毫秒也须要纳秒数。
使用Thread.sleep()方法就能把当前线程进入指定的时间进行休眠。
使用TimeUnit替代Thread.sleep
JDK1.5以后就引入了一个枚举TimeUnit,是对sleep的封装,咱们使用sleep要对时间进行换算,TimeUnit就省去了这一步骤。例如想让程序休眠2小时24分钟12秒44毫秒
TimeUnit.HOURS.sleep(2); //小时
TimeUnit.MINUTES.sleep(24); //1分钟
TimeUnit.SECONDS.sleep(12); //秒
TimeUnit.MILLISECONDS.sleep(44); //毫秒
sleep和wait的区别:
1)sleep是Thread的方法,而wait是Object的方法
2)wait方法的执行必须在同步的方法中进行,而sleep则不须要
3)线程在同步方法中执行sleep方法时,并不会释放monitor锁,而wait方法则会释放monitor的锁
4)sleep方法短暂休眠以后会主动退出阻塞,而wait方法则须要被其余线程中断后才能退出
yield方法属于启发式的方法,其会提醒调度器我愿意放弃当前CPU的资源,若是CPU的资源不紧张,则会忽略这种提醒。yield方法不是每次都生效的。
sleep和yield的区别:
sleep会致使当前线程暂停指定的时间,没有CPU的消耗,几乎百分百的完成了给定的时间休眠,而yield则不会。
yield只是对CPU的调度器的一个提示,若是CPU没有忽视,会致使上下文的切换。
线程的优先级比较高会优先获取CPU的调度,可是事实每每不会如你所愿,当CPU比较忙时,设置优先级可能会得到更多的CPU时间片,可是闲时优先级的高低几乎不会有任何做用。
setPriority() 设置优先级 getPriority() 获取当前线程的优先级
public long getId() 获取线程的惟一ID
public static native Thread currentThread() 用于返回当前线程的引用
getContextClassLoader() 获取线程上下文的类加载器,简单的来讲就是这个线程是有哪一个加载器加载的。
setContextClassLoader() 设置该线程的类加载器,这个方法能够打破java类加载器的父委托机制。
以下方法的调用可使当前线程进入阻塞状态,而调用interrupt方法能够打断阻塞。
1)OBject的wait方法
2)OBject的wait(long)方法
3)OBject的wait(long,int)方法
4)Thread的sleep(long)方法
5)Thread的sleep(long,int)方法
6)Thread的join方法
7)Thread的join(long)方法
8)Thread的join(long,int)方法
9)InterruptibleChannel的io操做
10)Selector的wakeup方法
一个线程调用了另外一个被阻塞线程的interrupt方法,则会打断阻塞,打断阻塞并不等于该线程的生命周期结束了,仅仅是打断了当前线程的阻塞状态。
某个A线程join,会使当前线程B进入等待状态,直到线程A结束生命周期或者达到给定的时间,此时B处于BLOCKED状态。
一、线程结束生命周期正常关闭,线程运行结束或者完成了本身的使命就会正常退出
二、捕获中断信号关闭线程,在线程里经过标识来中断线程
三、使用volatile开关控制,使用volatile修饰的开关flag关闭线程也是一种经常使用的方法
一个线程的执行单元中是不予许抛出checked异常的,不管是Thread中的run方法仍是Runnable中的run方法,若是运行中过程当中需捕获checked异常而且判断是否还有运行下去的必要,那么此时能够将checked异常封装成unchecked异常抛出进而结束线程的生命周期
所谓进程假死就是虽然进程存在,可是没有日志输出,程序不进行任何做业,看起来就想死了同样,但事实上他没有死,程序之因此出现这样的状况,绝大多数的缘由是某个线程阻塞了,或者线程出现了死锁的状况。
本文是参考 多线程与高并发编程 一书所作的笔记,都是精简事后的干货,但愿对你们有帮助。后续会继续更新 线程安全与同步、线程池原理、线程间的通讯等相关文章。