【并发编程】线程中的Sleep、Yield、Join等api方法方法线程状态转换

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

在上两篇中我们学习线程的概念和如何创建线程,在本篇中我们学习一些线程的方法和线程的状态。

方法

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());
    }
}

执行效果如下:能看到新建,运行状态,终止

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值