线程简介

不积跬步,无以至千里。不积小流,无以成江海。

线程的属性

属性 只读 描述
编号(ID) 类型:long,用于标识不同的线程,在同一时间系统中每个线程的 ID 都是唯一的。
名称(Name) 类型:String,允许相同。
类别(Daemon) 类型:boolean,true:守护线程,false:用户线程。设置该属性(setDaemon)时必须在调用start方法之前。
优先级(Priority) 类型:int,取值1~10,默认为5。

用户线程会阻止 java 虚拟机的正常停止,java 虚拟机只有在所有用户线程都执行结束之后才能正常停止。而守护线程不会阻止 java 虚拟机的正常停止,因此守护线程一般都执行一些重要性不是很高的任务。

如果java虚拟机是强制停止,即使是用户线程也无法阻止java虚拟机的停止。比如Liunx里的kill命令。

守护线程是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。

线程的调用

运行一个线程实际上就是让 java 虚拟机执行该线程的 run 方法。为此,我们首先要启动线程。Thread 类的 start 方法的作用就是启动线程,而这个线程具体何时能够运行是由线程调度器(Scheduler)决定的。因此,start 方法调用结束并不意味这相应线程已经开始执行。

线程属于“一次性用品”,我们不能重新调用一个已经运行结束的线程的 start 方法来使其重新运行。start 方法只能被调用一次,如果多次调用同一个线程的 start 方法会导致其抛出 IllegalThreadStateException 异常。

Thread 和 Runnable 的区别

从面向对象编程的角度来说:Thread 是基于继承的技术,Runnable 是基于组合(接口)的技术,因此,Runnable 的类与类之间的耦合性更低也更加灵活。

从对象共享的角度来说:Runnable 意味着多个线程实例可以共享一个 Runnable 实例,因此可能导致程序的运行结果出乎意料。

从对象创建的成本来说:创建一个线程实例比创建一个 Runnable 实例成本要昂贵一些。

Thread 类的 join 方法

等待相应线程执行结束,比如:线程A 调用了线程B 的 join 方法,那么线程A 会被暂停,直到线程B 运行结束。

1
2
3
A{
    B.join(5000);
}

其中5000表示 A线程最多等待 B线程5秒,如果超过5秒 B线程还未执行结束将不再等待。

停止线程

1、使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。

2、使用 stop 方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使用它们可能产生不可预料的结果。

3、使用 interrupt 方法中断线程。

暂停线程

yield() 方法的作用是放弃当前的 CPU 资源,将它让给其他的任务去占用 CPU 执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得 CPU 时间片。