线程基础
一,线程的创建
1.1 继承Thread类
public class ThreadCreateTest extends Thread {
@Override
public void run() {
// 逻辑
}
}使用:
public static void main(String[] args) {
ThreadCreateTest threadCreateTest = new ThreadCreateTest(); //1,创建继承的线程
threadCreateTest.start();//2,启动线程,不是直接调用run方法,直接调用run方法,就是普通的方发调用
//3,主线程的执行任务
}1.2 实现Runnable接口
public class ThreadCreateTest implements Runnable {
@Override
public void run() {
// 逻辑
}
}使用:
public static void main(String[] args) {
Thread thread = new Thread(new ThreadCreateTest());//1实现Runnable接口的类,传入Thread的构造方法
threadCreateTest.start();//2,启动线程,不是直接调用run方法,直接调用run方法,就是普通的方发调用
//3,主线程的执行任务
}1.3 实现Callable接口
public class ThreadCreateTest implements Callable<String> {
@Override
public String call() throws Exception {
// 逻辑
return null;
}
}Callable需要使用FutureTask类帮助执行,FutureTask类继承Future接口,Future接口还有如下方法:
- 判断任务是否完成:isDone()
- 能够中断任务:cancel()
- 能够获取任务执行结果:get()
Future的继承图如下:

使用:
public static void main(String[] args) {
// 1,通过Callable的实现类,创建Future的实例
FutureTask<String> ft = new FutureTask<String>(new ThreadCreateTest());
// 2,实现Runnable接口的类,传入Thread的构造方法,上图可以看出,FutureTask也是Runnable接口的实现类
Thread thread = new Thread(ft);
threadCreateTest.start();//3,启动线程,不是直接调用run方法,直接调用run方法,就是普通的方发调用
// 4,主线程的执行任务
}1.4 线程池
public class ThreadCreateTest implements Runnable {
@Override
public void run() {
// 逻辑
}
}public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(10); // 1,通过线程池工具类Executors创建线程池
threadPool.execute(new MyRunnable());// 2,为线程池附上任务
// 3,主线程的执行任务
}1.5 总结
①,实现接口和继承Thread类比较:
- 接口更适合多个相同的程序代码的线程去共享同一个资源。
- 接口可以避免java中的单继承的局限性。
- 接口代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现Runable或Callable接口的线程,不能直接放入继承Thread的类。
②,Runnable和Callable接口比较:
相同点:
- 两者都是接口;
- 两者都可用来编写多线程程序;
- 两者都需要调用依赖Threa类通过Thread.start()启动线程;
不同点:
- 实现Callable接口的线程能返回执行结果;而实现Runnable接口的线程不能返回结果;
- Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的不允许抛异常;
- 实现Callable接口的线程可以调用Future.cancel取消执行 ,而实现Runnable接口的线程不能
二,Thread
public class Thread implements Runnable {
private volatile String name;// 线程名字
private int priority;// 线程优先级(1~10)
private boolean daemon = false;// 守护线程
private ThreadGroup group;// 线程组
// 预定义3个优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
// 构造函数
public Thread();
public Thread(String name);
public Thread(Runnable target);
public Thread(Runnable target, String name);
public Thread(ThreadGroup group, Runnable target);// 线程组
public static native Thread currentThread(); // 返回当前正在执行线程对象的引用
public synchronized void start(); // 启动一个新线程
public void run(); // 线程的方法体,和启动线程没毛关系
// 让线程睡眠一会,由活跃状态改为挂起状态
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException;
// 打断线程 中断线程 用于停止线程 调用该方法时并不需要获取Thread实例的锁。
// 无论何时,任何线程都可以调用其它线程的interrupt方法
public void interrupt();
public static boolean interrupted(); // 将中断状态设置为false
public boolean isInterrupted()
public final int getPriority();// 获取线程优先级(1~10)
public final native boolean isAlive();// 线程是否处于活动状态
public static native void yield();// 交出CPU的使用权,从运行状态改为挂起状态
// 等待线程结束
public final void join() throws InterruptedException
public final synchronized void join(long millis)
public final synchronized void join(long millis, int nanos) throws InterruptedException
public final void setPriority(int newPriority); // 设置线程优先级
public final void setDaemon(boolean on);// 设置是否守护线程
public long getId() { return this.tid; }// 线程id
// 线程状态
public enum State {
NEW,// new 创建
RUNNABLE, // runnable 就绪
BLOCKED,// blocked 阻塞
WAITING,// waiting 等待
TIMED_WAITING, // timed_waiting
TERMINATED;// terminated 结束
}
}①,sleep()和wait()有什么区别
- 所属类不同:sleep是Thread类,wait是Object类
- 锁的释放:sleep不释放锁,wait释放锁
- 使用方式不同:sleep可以单独使用,wait需要一定要结合sycronized使用进行
②,start() 与 run()
- start()方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码。
- 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。
- 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。
③,interrupt()与interrupted()与isInterrupted()
interrupted()属于类方法,而interrupt()和isInterrupted()属于对象方法。
interrupt():不打断线程,将中断状态修改为true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。如果线程阻塞的调用sleep, wait, join 等方法,在别的线程中调用当前线程对象的interrupt方法,那么线程中断状态将被清除,重置为false,并抛出一个InterruptedException异常,会导致程序无限循环,所以需要在catch中重新调用intrrupt()方法,再次将中断状态设置为true。
interrupted(): 不打断线程,获取线程的中断状态,清除打断标记,将中断状态设置为false,连续再一次在调用interrupted()得到的结果就是false;即会清除打断标记,因为调用interrupt()打断的时候,将当断标记设为true,调用一次interrupted()后将打断标记设为了false;
isInterrupted():不打断线程,获取线程的中断状态,不会更改打断标记,即连续两次调用该方法得到的结果都是true。
三,线程状态
3.1 操作系统层面
这是从操作系统层面来描述线程的生命周期分为5个部分:分别是新建状态、就绪状态、运行状态,阻塞状态、死亡状态。
①,新建:new关键字创建了一个线程之后,该线程就处于新建状态;JVM为线程分配内存,初始化成员变量值
②,就绪:当线程对象调用了start()方法之后,该线程处于就绪状态;JVM为线程创建方法栈和程序计数器,等待线程调度器调度
③,运行:就绪状态的线程获得CPU资源,开始运行run()方法,该线程进入运行状态
④,阻塞:阻塞状态是指线程因为某种原因放弃了 cpu 使用权.阻塞状态分为三种情况:
等待阻塞:运行状态的线程调用了wait()方法后,该线程会释放它所持有的锁,然后被jvm放入到等待池中,只有等其他线程调用Object类的notify()方法或者norifyAll()方法时,才能进入重新进入到就绪状态。
同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,JVM就会把该线程设置为阻塞状态,一直到线程获取到同步锁,才能转入就绪状态。
其它阻塞:运行的线程在执行sleep()或者join()方法时,或者发出了I/O请求,JVM就会把该线程设置为阻塞状态,当sleep()状态超时、join()等待等待线程终止或者超时、或者I/O处理完毕时,线程重进转入到就绪状态。在这需要注意的是sleep()方法和wait()不同,sleep不会释放自身所持有的锁。
注意:程序调用了线程的suspend()方法将该线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法
⑤,死亡:线程会以如下3种方式结束,结束后就处于死亡状态:
- run()或call()方法执行完成,线程正常结束。
- 线程抛出一个未捕获的Exception或Error,线程异常结束。
- 调用该线程stop()方法来结束该线程,该方法容易导致死锁,不推荐使用。
3.2 Java API 层面
这是从 Java API 层面来描述的,根据 Thread.State 枚举,分为六种状态:

NEW 线程刚被创建,但是还没有调用 start() 方法
RUNNABLE当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的 【就绪状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为 是可运行)
BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分.
TERMINATED当线程代码运行结束
上图状态之间转换过程:
new -> runnable: 调用start()方法runnable <-> wating: wait和natify,natify唤醒后会进入monitor的EntryList中等待锁的竞争;获得锁成功变成runnable状态,获得锁失败变成blocked状态。runnable <-> wating:当前线程调用了t1.join()方法,当前线程就进入了wait状态,注意当前线程是在t1线程的监视器上等待的。当t1线程运行结束,或者调用了当前线程的interrupt()时,当前线程从wating变成runnablerunnable <-> wating:当前线程调用了LockSupport.park()方法,当前线程会从runnable变成wating状态,调用LockSupport.unpark(目标线程)方法或则时目标线程的interrupt(),可以将目标线程从wating变成Runnable状态。runnable <-> time_wating: wait(等待时间毫秒级)runnable <-> time_wating: join(等待时间毫秒级)runnable <-> time_wating: sleep(等待时间毫秒级)runnable <-> time_wating: LockSupport.parkNanos(等待时间纳秒级)runnable <-> blocked:当竞争锁失败的时候runnable <-> terminated:代码执行完毕