一.线程的状态
1.新建状态(New):
当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
2.就绪状态(Runnable):
当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
另外,start()方法是让线程进入就绪状态,而run()方法只是一个普通方法,当线程进入运行状态的时候会执行线程的run()方法。
public class TestRunAndStart {
public static void main(String[] args) {
new Thread("线程一") {
@Override
public void run() {
super.run();
System.out.println("当前运行的线程为:"Thread.currentThread().getName());
}
}.start();
new Thread("线程二") {
@Override
public void run() {
super.run();
System.out.println("当前运行的线程为:"Thread.currentThread().getName());
}
}.run();
}
}
运行结果:
当前运行的线程为:线程一
当前运行的线程为:main
3.运行状态(Running):
当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。
注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
4.阻塞状态(Blocked):
处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
(1).等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
(2).同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
(3).其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5.死亡状态(Dead):
线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
二.线程类的常用方法
1.构造方法
方法 | 作用 |
---|---|
Thread() | 创建新的线程对象,该线程默认名称为自动生成,形式为 “Thread-“+n ,其中的 n 为整数。 该方法通常用于创建匿名内部类并重写 run() 方法。 |
Thread(Runnable target) | 创建新的线程对象, target 对象为该新线程对象 run() 方法被调用的对象。 |
Thread(String name) | 创建新的线程对象, name 为该线程的名称。 |
Thread(ThreadGroup group,Runnable target) | 创建新的线程对象, group 为该线程所属的线程组。target 对象为该新线程对象 run() 方法被调用的对象。 |
Thread(ThreadGroup group,Runnable target,String name,long stackSize) | 创建新的线程对象,group 为该线程所属的线程组, target 对象为该新线程对象 run() 方法被调用的对象, name 为该线程的名称, stackSize 新线程的预期堆栈大小,为零时表示忽略该参数。 stackSize 参数(如果有)的作用具有高度的平台依赖性,在某些平台上, stackSize 参数的值无论如何不会起任何作用。通常建议,可以让虚拟机自由处理 stackSize 参数。 |
(1).Thread()
public void emptyConstitution(){
new Thread(){
@Override
public void run() {
System.out.println("新线程执行");
}
}.start();
}
控制台输出
新线程执行
(2).Thread(Runnable target)
public void runnableConstitution(){
new Thread(new Runnable() {
public void run() {
System.out.println("新的runnable方法");
}
}).start();
}
控制台输出
新的runnable方法
(3).Thread(String name)
public void nameConstitution(){
new Thread("MyThread"){
@Override
public void run() {
System.out.println("新的线程名为:"+this.getName());
}
}.start();
}
控制台输出
新的线程名为:MyThread
2.静态方法
方法 | 返回值类型 | 作用 |
---|---|---|
currentThread() | Thread | 返回对当前正在执行的线程对象的引用。 |
holdsLock(Object obj) | boolean | 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true 。 |
sleep(long millis) | void | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
sleep(long millis, int nanos) | void | 在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
yield() | void | 暂停当前正在执行的线程对象,并执行其他线程。 |
setDefaultUncaughtExceptionHandler (UncaughtExceptionHandler eh) | void | 设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。 |
(1).holdsLock(Object obj)
@Test
public void static_HoldsLock() {
Object lock = new Object();
synchronized (lock) {
System.out.println("synchronized代码块中:" + Thread.holdsLock(lock));
}
System.out.println("synchronized代码块外:" + Thread.holdsLock(lock));
}
控制台输出
synchronized代码块中:true
synchronized代码块外:false
(2).sleep(Object obj)
@Test
public void static_sleep() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("线程休眠了" + (end - start) + "毫秒");
}
控制台输出
线程休眠了1001毫秒
(3).yield()
//该变量为共享变量,volatile关键字保证了线程间的可见性
private volatile boolean static_Yield_Flag = false;
@Test
public void static_Yield() {
new Thread("新线程") {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
static_Yield_Flag = true;
System.out.println("isContinue状态修改为:ture");
System.out.println(Thread.currentThread().getName() + "结束");
}
}.start();
while (!static_Yield_Flag) {
Thread.yield();
}
System.out.println("主线程结束");
}
控制台输出
isContinue状态修改为:ture
新线程结束
主线程结束
(4).setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
@Test
public void static_SetDefaultUncaughtExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName()+"线程使用了全局异常处理器,异常信息:" + e.getMessage());
}
});
new Thread("新线程") {
@Override
public void run() {
System.out.println(1 / 0);//可以调用全局UncaughtExceptionHandler
}
}.start();
System.out.println("抛异常前");
//没有局部UncaughtExceptionHandler,返回当前ThreadGroup
System.out.println(Thread.currentThread().getUncaughtExceptionHandler());
throw new RuntimeException("抛异常");
}
控制台输出
抛异常前
java.lang.ThreadGroup[name=main,maxpri=10]
全局:/ by zero
java.lang.RuntimeException: 抛异常
at com.xin.thread.demo04_threadMethod._Main_ThreadMethodTest.static_SetDefaultUncaughtExceptionHandler(_Main_ThreadMethodTest.java:80)
......
在JUnit测试时主线程抛的异常不会走全局的UncaughtExceptionHandler(未知原因),而新创建的线程则会走全局UncaughtExceptionHandler。
然而在main方法调用时主线程抛的异常不能走UncaughtExceptionHandler,估计应该与JUnit内部实现有关(未看过JUnit源码不好下定论)。
3.实例方法
方法 | 返回值类型 | 作用 |
---|---|---|
getId() | long | 返回该线程的标识符。 |
getName() | String | 返回该线程的名称。 |
setName(String name) | void | 改变线程名称,使之与参数 name 相同。 |
getPriority() | int | 返回线程的优先级。 |
setPriority(int newPriority) | void | 更改线程的优先级。参数newPriority应大于等于1,小于等于10,否则会抛出IllegalArgumentException |
getState() | Thread.State | 返回该线程的状态。 该方法用于监视系统状态,不用于同步控制。 |
getThreadGroup() | ThreadGroup | 返回该线程所属的线程组。 |
isAlive() | boolean | 测试线程是否处于活动状态。 |
isDaemon() | boolean | 测试该线程是否为守护线程。 |
setDaemon(boolean on) | void | 将该线程标记为守护线程或用户线程。 |
(1).getState()
@Test
public void getState() throws InterruptedException {
Thread t = new Thread("新线程") {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "完成");
}
};
System.out.println("创建后状态为:" + t.getState());
t.start();
System.out.println("调用start()方法后状态为:" + t.getState());
Thread.sleep(50);
System.out.println("调用sleep()方法后状态为:" + t.getState());
Thread.sleep(150);
if (!t.isAlive()) {
System.out.println("线程方法后状态为:" + t.getState());
}
}
控制台输出
创建后状态为:NEW
调用start()方法后状态为:RUNNABLE
调用sleep()方法后状态为:TIMED_WAITING
新线程完成
线程方法后状态为:TERMINATED
(2).isAlive()
@Test
public void isAlive() throws InterruptedException {
Thread t = new Thread("新线程") {
@Override
public void run() {
System.out.println(getName() + "结束");
}
};
System.out.println(t.isAlive());
t.start();
System.out.println(t.isAlive());
Thread.sleep(100);
System.out.println(t.isAlive());
}
控制台输出
false
true
新线程结束
false
(3).setDaemon()
@Test
public void setDaemon() throws InterruptedException {
Thread t = new Thread("新线程") {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "运行中");
}
}
};
t.setDaemon(true);
t.start();
System.out.println(t.getName() + "为守护线程:" + t.isDaemon());
Thread.sleep(500);
}
控制台输出
新线程为守护线程:true
新线程运行中
新线程运行中
新线程运行中
新线程运行中
守护线程又叫后台线程,最常见的守护线程就是垃圾回收线程。当程序中所有正在运行中的线程都是守护线程时,程序就会退出(守护线程也会结束运行);而只要有一条还在运行的线程为用户线程(即非守护线程),则守护线程将会继续运行。