多线程技能
1.什么是进程?什么是线程?
我们可以把计算机上每一个正在进行的任务看做一个进程,比如说听音乐、做PPT、玩游戏等等。进程是受操作系统管理的基本运行单元。
而什么是线程呢?
线程是进程中独立的子部分,可以共享进程中的资源,而又有自己的小秘密。就如同进程在计算中一样的地位,所以也叫“轻量级的进程”
2.使用多线程
为什么要使用多线程呢?
因为现在的处理器为了提高效率,采取并发处理的方式,并发也就是看起来像是同时发生,但是同一时间处理器上只能执行一个进程,只是CPU的处理速度太快,我们看起来就像是一起发生一样。使用多线程的优势呢,就是可以同一时间内处理多种任务。使用多线程也就是使用异步,它的处理完全靠计算机调度,并不是按照代码的顺序来执行。谁的优先级更高,就更有可能获得CPU资源。
可以通过继承Thread类和实现Runnable接口。使用Runnable接口呢,避免的继承的单一性,当已经有了一个父类的的时候,就可以通过实现Runnable接口来实现多线程。
Thread类继承自Runnable接口,看源码发现Runnalbe接口里面只有一个run()方法,并没有启动多线程所需要的start()方法,所以需要把实现Runnable接口的实例对象作为一个target传给Thread类,由Thread类来启动多线程,而Thread类继承自Runnable,所以也完全可以把Thread子类的实例对象作为target传给Thread类,来创建多个线程,如果不传给Thread,只由Thread子类的实例对象来start()的话,一个target只能创建一个线程。
看一下Thread类的构造函数
3. 常用方法
currentThread()方法返回当前执行线程的信息。
isAlive()方法判断线程是否存活,也就是是否处在执行或者准备执行状态。
sleep() 线程睡眠,不会让出锁。
getId() 取得线程的唯一标识
4.停止线程
停止线程可以有三种方式:
1.run方法执行完线程终止
2.使用stop(),但是会带来不可预知的后果,已经被放弃使用
3.使用interrput()方法,这是现在大多使用的
单纯使用interrput()方法,并不会停止线程,只是会做上标记,那什么时候会停止线程呢?答案和下面两个判断方法搭配使用
这两个方法的区别是interrupted()会清除中断状态,也就是说在第一次判断已经中断以后,他会把这个状态清除掉。 第一次判断是true,第二次调用就会返回false。
也就是说流程是,使用interrput线程做上要停止的标记,然后使用上面两个方法判断一下是否要停止,如果是要停止,那么就在判断语句里面通过抛出异常或者return停止线程,不使用break是因为break以后下面的代码run方法里面break下面的代码还会执行。
当在沉睡中停止时,会抛出异常。
4.yield()放弃当前的CPU资源,但是放弃的时间不确定
5.线程的优先级
线程是并发执行的,采取竞争上岗的方式,那么谁能抢得过谁,与什么有关呢?
在这里,有一个词叫线程的优先级,通常线程优先级高的会优先获得CPU的资源,但这也不一定是绝对。
在这里需要注意的几点是:
1.如果A线程启动了B线程,那么B线程会继承A的优先级。也就是说在main()方法中,主线程启动了Thread线程,那Thread线程会和主线程拥有同样的优先级
2.代码流中A线程在B线程之前启动,但是A线程不一定比B线程先运行完,因为通常优先级高的会先获得执行权。那么优先级高的就会一直霸占CPU么?不会,
A和B还是会交替进行,但是通常优先级高的会先执行
3.这时候就来了例外了,就是优先级高的不一定先执行,这与第二条相反,体现出了线程的随机性。也就说,线程的优先级与打印顺序无关。他们之间的关系具有不确定性和随机性
6.守护线程
线程分为两种:用户线程和守护线程
守护线程正如其名,就是守护所有非守护线程的,只要程序里面还有一个非守护线程没有停止,守护线程就不会停止。当最后一个非守护线程被销毁,守护线程也就结束了它的工作。
我们最常知的守护线程是垃圾回收线程。