java线程的状态改变(练习)
改变线程中会用到的一些方法
方法 | 说明 |
---|---|
public static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) ,其休眠时间的精度取决于处理器的计时器和调度器。需要注意的是如果当前线程获得了锁,sleep方法并不会失去锁。 |
public static void yield() | 暂停当前正在执行的线程对象,并执行其他线程。 它会是当前线程让出CPU,但是,需要注意的是,让出的CPU并不是代表当前线程不再运行了,如果在下一次竞争中,又获得了CPU时间片当前线程依然会继续运行。 yield()的作用是让步,它能够让当前线程从“运行状态”进入到“就绪状态” |
public final void join() | 等待这个线程死亡, join方法可以看做是线程间协作的一种方式,很多时候,一个线程的输入可能非常依赖于另一个线程的输出 |
synchronized | synchronized是Java中的关键字,是一种同步锁,实现线程同步 |
wait() | wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”) |
notify()/notifyAll() | 则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。 |
1.2 线程的状态-计时等待(限期等待)
目的 : 本案例主要演示TIME_WAITING的状态转换。
需求编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> TIME_WAITING -> RUNNABLE -> TERMINATED
为了简化我们的开发,本次我们使用匿名内部类结合lambda表达式的方式使用多线程。
代码实现
public class ThreadStateDemo01 {
public static void main(String[] args) throws InterruptedException {
//定义一个内部线程
Thread thread = new Thread(() -> {
System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState());
try {
//休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4.执行Thread.sleep(long)完成之后,线程的状态:" + Thread.currentThread().getState());
});
//获取start()之前的状态
System.out.println("1.通过new初始化一个线程,但是还没有start()之前,线程的状态:" + thread.getState());
//启动线程
thread.start();
//休眠50毫秒
Thread.sleep(50);
//因为thread1需要休眠100毫秒,所以在第50毫秒,thread处于sleep状态
System.out.println("3.执行Thread.sleep(long)时,线程的状态:" + thread.getState());
//thread1和main线程主动休眠150毫秒,所以在第150毫秒,thread早已执行完毕
Thread.sleep(100);
System.out.println("5.线程执行完毕之后,线程的状态:" + thread.getState() + "\n");
}
}
控制台输出
1.通过new初始化一个线程,但是还没有start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.执行Thread.sleep(long)时,线程的状态:TIMED_WAITING
4.执行Thread.sleep(long)完成之后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED
1.3 线程的状态-等待(无限期等待)
目的 : 本案例主要演示WAITING的状态转换。
**需求 :**编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> WAITING -> RUNNABLE -> TERMINATED
代码实现 :
package thread;
public class ThreadStateDemo02 {
public static void main(String[] args) throws InterruptedException {
//定义一个对象,用来加锁和解锁
Object obj = new Object();
//定义一个内部线程
Thread thread1 = new Thread(() -> {
System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState()); // RUNNABLE
synchronized (obj) {
try {
//thread1需要休眠100毫秒
Thread.sleep(100);
//thread1 100毫秒之后,通过wait()方法释放obj对象是锁
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("4.被object.notify()方法唤醒之后,线程的状态:" + Thread.currentThread().getState()); // RUNNABLE
});
//获取start()之前的状态
System.out.println("1.通过new初始化一个线程,但是还没有start()之前,线程的状态:" + thread1.getState()); // NEW
//启动线程
thread1.start();
//main线程休眠150毫秒
Thread.sleep(150);
//因为thread1在第100毫秒进入wait等待状态,所以第150秒肯定可以获取其状态
System.out.println("3.执行object.wait()时,线程的状态:" + thread1.getState());//WAITING
//声明另一个线程进行解锁
new Thread(() -> {
synchronized (obj) {
//唤醒等待的线程
obj.notify();
}
}).start();
//main线程休眠10毫秒等待thread1线程能够苏醒
Thread.sleep(10);
//获取thread1运行结束之后的状态
System.out.println("5.线程执行完毕之后,线程的状态:" + thread1.getState() + "\n"); // TERMINATED
}
}
控制台输出结果
1.通过new初始化一个线程,但是还没有start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.执行object.wait()时,线程的状态:WAITING
4.被object.notify()方法唤醒之后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED
1.4 线程的状态-阻塞
目的 : 本案例主要演示BLOCKED的状态转换。
需求:编写一段代码,依次显示一个线程的这些状态:NEW -> RUNNABLE -> BLOCKED -> RUNNABLE -> TERMINATED
package thread;
public class ThreadStateDemo03 {
public static void main(String[] args) throws InterruptedException {
//定义一个对象,用来加锁和解锁
Object obj2 = new Object();
//定义一个线程,先抢占了obj2对象的锁
new Thread(() -> {
synchronized (obj2) {
try {
Thread.sleep(100); //第一个线程要持有锁100毫秒
obj2.wait(); //然后通过wait()方法进行等待状态,并释放obj2的对象锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//定义目标线程,获取等待获取obj2的锁
Thread thread = new Thread(() -> {
System.out.println("2.执行thread.start()之后,线程的状态:" + Thread.currentThread().getState()); // RUNNABLE
synchronized (obj2) {
try {
Thread.sleep(100); //thread3要持有对象锁100毫秒
obj2.notify(); //然后通过notify()方法唤醒所有在ojb2上等待的线程继续执行后续操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("4.阻塞结束后,线程的状态:" + Thread.currentThread().getState()); // RUNNABLE
});
//获取start()之前的状态
System.out.println("1.通过new初始化一个线程,但是还没有thread.start()之前,线程的状态:" + thread.getState()); // NEW
//启动线程
thread.start();
//先等100毫秒
Thread.sleep(50);
//第一个线程释放锁至少需要100毫秒,所以在第50毫秒时,thread正在因等待obj的对象锁而阻塞
System.out.println("3.因为等待锁而阻塞时,线程的状态:" + thread.getState()); // BLOCKED
//再等300毫秒
Thread.sleep(300);
//两个线程的执行时间加上之前等待的50毫秒总共是250毫秒,所以第300毫秒,所有的线程都已经执行完毕
System.out.println("5.线程执行完毕之后,线程的状态:" + thread.getState()); //TERMINATED
}
}
控制台输出结果
1.通过new初始化一个线程,但是还没有thread.start()之前,线程的状态:NEW
2.执行thread.start()之后,线程的状态:RUNNABLE
3.因为等待锁而阻塞时,线程的状态:BLOCKED
4.阻塞结束后,线程的状态:RUNNABLE
5.线程执行完毕之后,线程的状态:TERMINATED
上面我们提到了锁的概念,因为锁也算一个小节,所以详情请点击 java多线程-锁(Lock)