在程序开发中, 必定遇到并发编程的场景, 虽然咱们大部分时间并不直接使用Thread, 可是Thread是多线程的基础, 面试中也会老是被问到与线程有关的问题; 那么线程都有哪些知识呢? 最近在研究线程的源码的时候也总结了关于线程一些基本知识;
线程是轻量级的进程, 是操做系统调度任务到CPU的最小单元;java
一、多线程编程可以最大程度的利用多核设备上面的CPU资源, 保证任务处理的足够快, 及时响应客户端的额请求面试
二、线程的建立的代价比建立进程的代价小不少, 同时多线程的上下文切换也更快; 《操做系统概念 第六版》 在Solaris 2上面, 建立进程比建立线程慢30倍, 而进程的上下文切换比线程的上下文切换慢5倍;编程
查看java.lang.Thread的源码有以下代码:多线程
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
即 新建状态并发
二、RUNNABLE: 当一个线程处于运行中或者等待CPU调度的时候, 状态就是 RUNNABLE
状态; 有些地方也称为 就绪状态
函数
三、BLOCKED: 当一个线程在等待别的线程释放锁资源的时候, 状态就是BLOCKED
, 或者在该线程获取到锁以后, 在同步代码块里面调用了Wait方法, 这时候释放锁, 在获取到其余线程的notify或者notifyAll通知以后, 从新进入 同步代码块这段时间 该线程也是BLOCKED
状态的;spa
四、WAITING: 当正在运行的线程调用了Object.wait()
方法 或者 Thread.join()
方法 或者 LockSupport.park()
方法以后, 会进入到WAITING
状态操作系统
五、TIMED_WAITING: 当正在运行的线程调用Object.wait(n)
或者 Thread.join(n)
或者 LockSupport.parkUntil(blocker, n)
会进入到 TIMED_WAITING
状态线程
六、TERMINATED: 当线程结束后, 会进入到 TERMINATED
状态.翻译
状态转换以下, 该图中比Java的状态多了一个RUNNING状态, 来区别 线程的就绪状态 与 运行状态 更加方便读者理解;
下面来看一下线程的状态转换用Java怎么实现:
如上面所述: 刚刚建立的线程处于NEW状态, 那么咱们能够经过以下代码打印其状态:
Thread thread = new Thread(new Runnable() { public void run() { } }); System.out.println(thread.getState());
那么线程如何进入到RUNNABLE
状态呢? 调用Thread
的start
方法便可; 咱们在Runnable的实现里面增长对于当前线程状态的打印便可:
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { System.out.println("线程进入:" + Thread.currentThread().getState()); } }); System.out.println(thread.getState()); thread.start(); }
那么线程怎么进入到TIMED_WAITING
状态呢? 经过调用 sleep(n)
join(n)
或者 wait(n)
均可以进入到TIMED_WAITING
状态:
调用Thread.sleep()
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Thread.sleep(1000 * 60); } catch (InterruptedException e) { e.printStackTrace(); } } }); System.out.println(thread.getState()); thread.start(); }
调用obj.wait(time)
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Client.class.wait(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); System.out.println(thread.getState()); thread.start(); }
上图中表示: 在Client.class上面等待; 等待其余对象调用Client.class.notify()方法或者等待时间到期.
调用thread.join(time)
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Client.class.wait(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Client.class对象上等待超时"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { thread.join(50 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1结束"); } } }); thread2.start(); }
表示 第二个线程在等待第一个线程执行完成或者超时;
若是想要一个线程进入到WAITING状态, 那么只须要跟上面步骤同样, Thread.sleep()除外, 可是调用的时候不要传超时时间便可;
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Client.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("被其余线程调用Client.class.notify()唤醒"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { thread.join(50 * 1000); Client.class.notify(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1结束"); } } }); thread2.start(); }
只要是没有时间的等待都会处于WAITING
状态, 好比把上面代码修改一下, 换成join()
也可让线程处于 WAITING
状态:
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Client.class.wait(50 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("被其余线程调用Client.class.notify()唤醒"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { System.out.println("即将进入等待线程1完成的状态"); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1结束"); } } }); thread2.start(); }
如上代码表示线程2会在线程1执行结束以后再结束, 因此线程2就会进入到WATIING
状态
上面已经看到, 经过调用线程的函数就能够控制线程的状态, 那么如何进入到BLOCKED状态呢?进入到BLOCKED状态, 按照上面的转换图 能够翻译为 多个线程出现竟态的时候, 其余线程会进入BLOCKED状态, 只有一个线程会在RUNNABLE状态,好比以下代码:
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("线程进入:" + Thread.currentThread().getState()); try { Thread.sleep(1000 * 50); } catch (InterruptedException e) { e.printStackTrace(); } } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { System.out.println("即将进入等待线程1完成的状态"); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1结束"); } } }); thread2.start(); }
固然, 对于A线程调用了Object.class.wait()
方法释放锁以后, 最后被其余线程调用Object.class.notify()
A线程再次进入RUNNABLE以前的状态就是 BLOCKED
;