Java并发编程之线程基础
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(被终止)
线程各个状态的转换: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