目录

一、优先级

二、线程的生命周期

三、线程中的常用方法

常用方法

注意事项

给出一道面试题


一、优先级

在Java程序中,一个程序通常会有多个线程同时进行来执行多个任务,使CPU的资源利用率得到最大化。但是我们知道,对于单核CPU来说多线程是通过在多个线程之间快速切换来实现所谓的“多线程同时进行”的。也就是说,我们多个线程并不是真正的同时执行,而是在交替执行,CPU在执行完一次任务后会释放资源来执行下一个任务,那么在选择下一次任务时能不能通过某种方法来使某个线程获得CPU的概率更大呢?答案就是给各个线程规定一个优先级,优先级高的线程较优先级低的线程更有可能获得下一次CPU执行权。

在Java中,线程的优先级从1到10分为十个优先级,数字越高代表优先级越高,越有可能获得下一次CPU执行权。同时Thread类中声明了三个静态变量来表示三个特殊优先级,分别是:

MAX_PRIORITY:10     MIN_PRIORITY:1     NORM_PRIORITY:5

我们可以通过使用如下方法来获取一个线程的优先级

public final int getPriority()

也可以使用如下方法来设置一个线程的优先级

public final void setPriority(int newPriority)

例:创建一个线程thread1,修改其优先级为8,然后再创建一个新线程thread2,比较两个线程优先级

package t;

//通过继承Thread类的方法创建一个线程
public class ThreadTest1 extends Thread{

    //重写run()方法

    public void run() {

        for(int i=1;i<100;i++) {

        System.out.println("i="+i);

        }

    }

}





package t;

public class ThreadTest {

    public static void main(String []args) {

        //创建xianchengthread1

        ThreadTest1 thread1=new ThreadTest1();

        //设置其优先级为8
    
        thread1.setPriority(8);

        //创建线程thread2

        ThreadTest1 thread2=new ThreadTest1();
    
        //获取两个线程的优先级

        int priority1=thread1.getPriority();

        int priority2=thread2.getPriority();

        //输出线程优先级之差

        System.out.println(priority1-priority2);

        //启动线程

        thread1.start();

        thread2.start();

    }

}

二、线程的生命周期

就像人从出生到死亡分为婴儿、少年...老年、死亡等多个阶段一样,线程从创建到死亡也分为多个阶段,每个阶段有各自的特性。

线程分为创建、就绪、运行、阻塞、死亡五种状态

接下来分别介绍五种状态分别对应的情形

  1. 新建:当一个线程创建但没有执行start()方法时,称该线程处于创建状态。
  2. 就绪:新建的下一个状态,当调用了start()方法后等待CPU分配资源来运行线程的过程叫做就绪状态。
  3. 运行:当CPU分配资源给就绪状态的线程后,改线程就会进入运行状态。
  4. 阻塞:当一个线程调用某个方法后,会使自己进入一个无法获取CPU资源的状态,这个状态就是阻塞状态。
  5. 死亡:顾名思义,当一个线程任务结束后便会进入死亡状态。

在这几个状态中有如下注意点(涉及到上面没讲的方法见后面的常用方法部分)

  1. 能使线程进入阻塞状态的方法有:sleep(long millis)、join()、wait()。
  2. CPU运行完线程切换到下一个线程后,该线程处于就绪状态不是阻塞状态,要区分阻塞和就绪状态。
  3. 当将线程thread1作为参数创建新线程thread2调用thread2.start()后,thread1线程仍处于新建状态,但是线程thread2处于就绪(运行)状态。(这是因为调用的是thread2的start()方法)
  4. 处于死亡状态的线程没办法再使用。

三、线程中的常用方法

我们先给出常用的方法然后再给出相关注意事项

常用方法:

public synchronized void start():启动一个线程

public void run():需要重写的方法,方法体就是这个线程要干的事

public static native Thread currentThread():获取调用该代码的线程

public final String getName():获取线程的名字

public final synchronized void setName(String name):设置线程的名字

public static native void yield():释放CPU资源进入就绪状态

public final void join():在a线程中调用b线程的join()方法会使a线程进入阻塞状态直到b线程运行结束

public static native void sleep(long millis):使线程进入阻塞状态millis毫秒

public final native boolean isAlive():判断一个线程是否存活

public final int getPriority():获取一个线程的优先级

public final void setPriority(int newPriority):设置线程优先级为newPriority

public void wait():使线程进入阻塞状态,直到被别的线程调用notify()唤醒

public void notify():唤醒进入wait状态中优先级最高的线程

public void notifyAll():唤醒所有进入wait状态的线程

注意事项:

  1. 使用yield后不意味着接下来运行的一定不是该线程,它有可能刚释放CPU资源后 立马又获取了CPU资源 。
  2. 使用sleep方法使线程进入阻塞状态后,该线程并不会释放锁,也就是说其他线程也没办法使用该同步代码。
  3. run()方法没有提供throws来解决异常,所以sleep中的异常不能通过throws方法来解决。
  4. wait()和notify()方法是定义在Object类中的,不是定义在Thread类中的。
  5. wait状态线程被notify后会继续执行wait后面的代码。
  6. 如果所有线程都进入wait状态,程序不会报错也不会停止,要避免出现这种情况。

给出一道面试题

说说sleep和wait的异同

相同点:都会使一个线程进入阻塞状态

不同点:1.sleep()是定义在Thread类中的而wait()是定义在Object类中的。

              2.sleep()不会释放同步锁而wait()会释放同步锁