在上两篇中我们学习线程的概念和如何创建线程,在本篇中我们学习一些线程的方法和线程的状态。
方法
Sleep:线程睡眠
线程休眠指的是让线程暂缓执行以一下,等到了预计时间之后再恢复执行参数是毫秒。当线程启动后,再调用sleep方法,可以让线程进入特定时间的阻塞状态,当时间过去后,在进入运行态。
示例代码如下:
public class T03_Sleep {
public static void main(String[] args){
testSleep();
}
static void testSleep(){
new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("A" + i+ " "+new Date().toString());
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}).start();
}
}
当启动此线程后,打印循环变量和当前时间,发现每隔一秒打印一次。这就是我们让线程每打印一次就睡眠一秒,所以才会如从。

值得注意的一点是sleep不会释放对象锁,即使当前线程休眠了,其他线程也无法拿到该runable对象,当该线程休眠结束后,继续执行;
Yield:线程让步
yield() 方法和 sleep() 方法类似,也不会释放“锁标志”,区别在于,它没有参数,即 yield() 方法只是使当前线程重新回到可执行状态,将CPU让出来。然后CPU从所有可执行状态的线程中选择线程执行。所以执行 yield() 的线程有可能在进入到可执行状态后马上又被执行,也可能执行别的线程,他所起到的作用就是将CPU让出,重新选择线程。另外 yield() 方法只能使同优先级或者高优先级的线程得到执行机会,这也和 sleep() 方法不同。
public class T03_Yield {
public static void main(String[] args) {
testYield();
}
static void testYield() {
new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("A" + i);
if (i % 10 == 0) Thread.yield();
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("-----------B" + i);
if (i % 10 == 0) Thread.yield();
}
}).start();
}
}
每次对10取余,当余数为零时,执行yield方法(),运行的部分结果如下:

Join:线程等待
若一个线程1需要等待另一个线程2执行完毕后再恢复执行,可以在线程1中调用线程2的join()方法。
public class T03_Join {
public static void main(String[] args){
testJoin();
}
static void testJoin(){
Thread t1 = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
Thread t2 = new Thread(()->{
try {
t1.join();
}catch (InterruptedException e){
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
System.out.println("B" +i);
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
因为t2在执行时,调用了t1的join方法,所以t2要想执行完毕,必须等待t1执行完毕。执行效果图如下:

currentThread:获取线程实例
获取实例后,可以从当前线程实例中拿出属性值
public static void main(String[] args) {
//获取线程实例
Thread s = Thread.currentThread();
//获取实例后可以从实例中拿当前线程的的属性
//获得当前线程名称
System.out.println(s.getName());
//获取当前线程状态
System.out.println(s.getState());
//获得优先级
System.out.println(s.getPriority());
//是否存活
System.out.println(s.isAlive());
}
运行结果如下
setPriority :设置线程优先级
Thread 有自己的最小和最大优先级数值,范围在 1-10。如果不在此范围内,则会报错。另外如果设置的 priority 超过了线程所在组的 priority ,那么只能被设置为组的最高 priority 。最后通过调用 native 方法 setPriority0 进行设置。
/**
* 改变线程的优先级
*/
public class PriorityTest extends Thread{
//定义一个有参数的构造器,用于创建线程时指定name
public PriorityTest(String name){
super(name);
}
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println(getName()+",其优先级是:"+getPriority()+",循环变量的值为:"+i);
}
}
public static void main(String[] args){
//改变主线程的优先级
Thread.currentThread().setPriority(6);
for (int i = 0; i < 30; i++) {
if (i==10) {
PriorityTest low = new PriorityTest("低级");
low.start();
System.out.println("创建之初的优先级:" + low.getPriority());
//设置该线程为最低级的优先级
low.setPriority(Thread.MIN_PRIORITY);
}
if (i==20) {
PriorityTest high = new PriorityTest("高级");
high.start();
System.out.println("创建之初的优先级:" + high.getPriority());
//设置该线程为最高级的优先级
high.setPriority(Thread.MAX_PRIORITY);
}
}
}
}
运行结果如下:

一直循环到50,之后是另一个线程循环:

线程状态
java中的线程的生命周期大体可分为5种状态。从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。
1. 新建(NEW):新创建了一个线程对象。
2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
- (一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
- (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
- (三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
这几种状态的转换如图:

可以通过以下的代码看到一些线程的状态:
public class T04_Threadstate {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println(this.getState());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getState());
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getState());
}
}
执行效果如下:能看到新建,运行状态,终止

本文深入探讨Java中线程的控制方法,包括Sleep、Yield和Join的使用,以及如何通过currentThread和setPriority调整线程。同时,详细解析了线程的五种生命周期状态,帮助读者理解线程的运行机制。
218

被折叠的 条评论
为什么被折叠?



