1.线程的概念

提到线程,我们就不得不提到另外一个与之相似的概念:进程。何为进程?进程就是一个程序一次动态的执行过程,即计算机中一个任务的执行。在使用计算机的过程中,例如:打开酷狗软件听音乐,登录QQ与好友互动,Java虚拟机的启动等等,都对应着计算机中的一个个进程,进程是操作系统进行资源分配的基本单位
那么什么又是线程呢?如果进程是一个大的任务,那么线程就是这个大任务中一个个具体的子任务,我们可以把线程看成是一个更加轻量级的进程。在使用酷狗软件时,我们既可以一边播放音乐,一边下载歌曲,同时还可以设置背景颜色,这些一个个的具体操作就是线程,线程是CPU调度的基本单位

2.线程的创建

创建线程有两种常见的方式:继承java.lang.Thread类和实现Runnable接口
继承Thread类,重写run方法,在run方法中定义需要执行的任务

public class MyThread extends Thread {
    @Override
    public void run(){}  
}
Thread thread = new MyThread();
thread.start(); 

实现Runnable接口,重写run方法,在run方法中定义需要执行的任务

Runnable r = () -> {
  // 具体实现
};
Thread thread = new Thread(r);
thread.start();

创建线程的两种方式的比较
相比于第一种继承Thread类创建线程的方式,更加推荐使用第二种方式,因为第二种方式实现了线程的创建与具体执行的任务之间的解耦,并且在实现Runnable接口时同时可以继承其它的类

3.线程的状态

线程有6种状态:
NEW(新建)
RUNNABLE(可运行)
BLOCKED(阻塞)
WAITING(等待)
TIMED_WAITING(计时等待)
TERMINATED(被终止)
线程各个状态的转换:
线程状态转换.png

4.线程常用方法

void start()
调用start()方法将会启动一个新的线程,当该线程获得CPU执行权后,将引发调用run()方法,执行用户定义的子任务

void run()
当启动一个新的线程并获得CPU执行权后,便自动调用run()方法去执行具体的子任务。 注意,如果直接调用run()方法,那么系统将不会启动一个新的线程,而是将run()方法作为一个普通方法运行

static native void sleep(long millis)
sleep()方法让线程休眠给定的时间,同时放弃CPU的执行权,此时线程进入TIMED_WAITING状态
注意,如果当前线程持有某个对象的锁,调用sleep()方法不会释放该锁

static native void yield()
调用yield方法会让当前线程放弃CPU的执行权,它跟sleep方法类似,同样不会释放锁,但是yield不能控制具体的交出CPU的时间
另外,yield方法只能让拥有相同优先级的线程有获取CPU执行权的机会
注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回可运行状态

final void join()
调用thread.join()方法,当前线程将等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待指定的时间

void interrupt()
向线程发送中断请求,线程的中断状态将被置为true。如果目前该线程被一个sleep调用阻塞,那么InterruptedException异常被抛出

boolean isInterrupted()
测试线程是否被终止,不改变中断状态

static boolean interrupted()
测试当前线程(正在执行这一命令的线程)是否被中断
注意:调用该方法将会使当前线程的中断状态重置为false