提示:有关线程六大状态, 以及创建线程的五种方法
线程
- 线程
- 线程状态
- NEW
- RUNNABLE
- BLOCKED
- WAITING
- TIMED_WAITING
- TERMINATED
- 线程状态转化图
- 线程创建使用方式
- ps
线程
线程状态
操作系统的线程主要有以下三个状态:
- 就绪状态(ready):线程正在等待使用 CPU,经调度程序调用之后进入 running 状态。
- 执行状态(running):线程正在使用 CPU。
- 等待状态(waiting): 线程经过等待事件的调用或者正在等待其他资源(如 I/O)。
Java中线程层面状态有六种, 其实这里注释很详细, 可以尝试翻译理解
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
NEW
处于 NEW 状态的线程此时尚未启动。这里的尚未启动指的是还没调用 Thread 实例的start()
方法。
RUNNABLE
表示当前线程正在运行中。处于 RUNNABLE 状态的线程在 Java 虚拟机中运行,也有可能在等待 CPU 分配资源。
BLOCKED
阻塞状态。处于 BLOCKED 状态的线程正等待锁的释放以进入同步区。
WAITING
等待状态。处于等待状态的线程变成 RUNNABLE 状态需要其他线程唤醒。
调用下面这 3 个方法会使线程进入等待状态:
Object.wait()
:使当前线程处于等待状态直到另一个线程唤醒它;Thread.join()
:等待线程执行完毕,底层调用的是 Object 的 wait 方法;LockSupport.park()
:除非获得调用许可,否则禁用当前线程进行线程调度
TIMED_WAITING
超时等待状态。线程等待一个具体的时间,时间到后会被自动唤醒。
调用如下方法会使线程进入超时等待状态:
Thread.sleep(long millis)
:使当前线程睡眠指定时间;Object.wait(long timeout)
:线程休眠指定时间,等待期间可以通过notify()
/notifyAll()
唤醒;Thread.join(long millis)
:等待当前线程最多执行 millis 毫秒,如果 millis 为 0,则会一直执行;LockSupport.parkNanos(long nanos)
: 除非获得调用许可,否则禁用当前线程进行线程调度指定时间;LockSupport.parkUntil(long deadline)
:同上,也是禁止线程进行调度指定时间;
TERMINATED
终止状态。此时线程已执行完毕。
线程状态转化图
线程创建使用方式
本质上就两种方式, 一种实现接口, 一种继承Thread
- 实现Runnable
class MyRunnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestDemo2 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
while(true){
System.out.println("hello main");
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 实现Callable
- 实现Callable是带有返回值的, 可以使用FutureTask封装
public class MyCallable implements Callable<Integer> {
public Integer call() {
return 123;
}
}
------------------------------------------------------------------
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread thread = new Thread(ft);
thread.start();
System.out.println(ft.get());
}
- 继承Thread
class MyThread extends Thread{
@Override
public void run() {
System.out.println("hello thread");
}
}
public class TestDemo {
public static void main(String[] args) {
Thread t = new MyThread();//向上转型
t.start();
}
}
这里我们为什么使用t.start() 而不是t.run()
t.run()只是调用了MyThread中的run方法, 并不是起了一个线程, 这不叫多线程
而t.start()是真正创建了一个线程
-
线程池
public class TestDemo3 { public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { while(true) { System.out.println("Hello Thread"); try{ Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); } } } }; t.start(); } }
-
Lamdba表达式
public static void main(String[] args) {
Thread t = new Thread(()->{
while(true){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.run();
}
实现Runnable和Callable本质上是任务, 可以理解为创建了一个可以在线程中运行的任务, 而不是真正的线程. 而实现Thread才是真正的创建了线程
实现接口和继承Thread哪个更好?
- 当然是实现接口, Java本身不支持多继承, 继承一个Thread就不能再继承别的了
- 继承Thread开销过大
- 接口的写法中线程和任务是分离的。更好的解耦合。关联关系越紧密,就认为耦合性越高。此时线程的内容本身和线程的关系不大。那么以后更改任务不采用多线程执行,代码的改动也不是很大
ps
todo:线程池相关后面补