2、线程的状态和调度学习笔记


1、线程的状态

 

 

1.1 新生状态

    新生状态是指new创建了一个新线程,但还没有调用他的start方法

 

1.2 可运行状态

   调用了start方法之后,线程就有了运行的机会,处于可运行状态。

   此时线程对象可能正在运行,也可能尚未运行。

         为什么这么说呢?因为线程的运行方式是一种抢占的运行方式,在同一个时刻可能会有多个线程都处于可运行状态,那么这个时候调度程序只会选择一个程序让他运行

1.3 被阻塞状态

            被阻塞状态是一种“不可运行”的状态,而处于这种状态的线程在得到一个特定的事件之后,可能会返回到可运行状态。

       导致线程被阻塞的原因有这么几个:

       1、第一种情况:我们调用了一个Threadl类的静态方法Sleep,当前正在执行的线程会马上进入阻塞状态,并且主动放弃所占用的处理器资源。

         这个时候,线程调度程序就会在可运行状态的线程当中重新选择一个线程,让他开始执行。

 

2、第二种情况:如果一个线程需要用到一个读写操作的结果,但这个结果尚未完成,这个时候线程就会被阻塞。

 

3、第三种情况:如果一个线程的执行需要得到一个对象的锁,而这个对象的锁正被别的线程占用,那么这个线程也会被阻塞。需要等到这个对象的锁被其他线程释放后才能继续执行。

 

4、第四种情况:当一个线程对象执行了suspend方法被挂起时,线程也会被阻塞。Suspend是个很危险的方法,因为他容易引起死锁,已经被jdk列为过期的方法,所以以后不要使用这个方法。

 

1.3 死亡状态

      当一个线程的run方法运行完毕之后,或者运行过程中出现没有被捕获的异常时,这个线程就会进入死亡状态。

      处于死亡状态的线程可能不会马上释放所占的内存资源,

      如果我们尝试在一个已经死亡的线程上调用start方法会报异常。即一个线程对象只能运行一次。

 

 

2、线程的优先级

       优先级是一个整数值,值大小代表了这个线程跟其他线程竞争处理器资源时得到执行机会的多少。值越大,机会越大。

       那怎么设置线程的优先级呢?

       

 


   要注意的是,优先级的值是有范围的

1、线程的优先级的范围可能要根据操作系统的不同而不同

2、通常情况下,优先级的值最大值是10,最小是1,默认是5

 

3、线程的调度

3.1  join()方法

1joinThread类中定义的非静态方法

2、他的作用是阻塞指定的线程直到另一个线程完成以后再继续执行

 

假如有两个线程AB,在A线程的run方法中,调用b.join(),那么他的意思不是说把线程B加入到A的末尾,等A执行完了之后B才能继续执行,正好相反,他的意思是将A加入到B的末尾,等B执行完毕之后A才能继续执行,而在B执行之前A一直处于阻塞状态。

实例:

package com.pb.thread.demo;

/*
 * join()方法的特点
 * 1、当前线程会被挂起,让join进来的线程执行
 * 2、join进来的线程在没有执行完毕之前,会一直阻塞当前线程
 * 
 * mian方法启动时,就会创建当前java程序的主线程!!!
 */
public class JoinTest extends Thread {
    public JoinTest(String name)
    {
        super(name);
    }
    
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(getName()+i);
        }
    }
    
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        for (int i = 0; i < 10; i++) {
            if(i==5) {
                Thread jThread= new JoinTest("半路杀出的线程"+i+"--");
                try {
                    jThread.start();
                    jThread.join();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
            System.out.println(Thread.currentThread().getName()+i);//输出主线程的名字
        }
    }

}

 

 

 

 

3.2  sleep()方法

      1、是Thread类中的静态方法

      2、指定休眠多长时间(单位毫秒),让当前线程停止执行并转入被阻塞状态,这个时候其他正在等待被执行的线程将被有机会获得处理器执行

 

package com.pb.thread.demo.Sleep方法;

public class NewThread extends Thread {
   public void run()
   {
       for (int i = 0; i < 20; i++) {
        System.out.println("新线程的i值是"+i);
    }
   }
}

package com.pb.thread.demo.Sleep方法;

public class Wait {
    public static void bySec(long s)
    {
        for (int i = 0; i < s; i++) {
            System.out.println(i+1+"秒");
            try {
                Thread.sleep(1000);//休眠一秒
                
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }
}
package com.pb.thread.demo.Sleep方法;


/*
 * sleep方法的作用是
 * 1、将当前线程挂起(就是暂停当前线程的执行),并阻塞指定的时间
 * 2、当前线程挂起后,就会释放系统资源,让别的线程执行
 */
public class TestWait {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread nThread=new NewThread();
        nThread.start();
        
        System.out.println("开始等待");
        
        
        Wait.bySec(5);
        System.out.println("恢复运行");
    } 

}

 

 

 

3.3  yield()方法

1Thread类的静态方法

2、他的作用是让当前线程转入可运行的状态,即这个当前线程仍然可以和其他的等待执行的线程竞争处理器资源。

 

 

3.4  setDaemon()方法

       

 

1指定一个线程是否是后台线程。

什么是后台线程?

他是一个在后台运行的线程,他从属于创建他的线程,因此在创建后台线程的线程结束时,这个后台线程也随之消亡。

2除了后台线程之外,其他的线程都统称为用户线程。 

用户线程由自己的生命周期,不依赖于创建他的父线程。

3、我们创建线程的时候,都是用户线程。

4、应该注意一点,我们只能在线程启动之前将他们设置为后台线程,而不能是启动之后再设置。

 


作者:拭不去の泪痕,发布于:2019/08/06
原文:https://www.cnblogs.com/schangxiang/p/11300873.html