BLOCKED WAITING wait join TIMED_WAITING sleep join wait 守护线程的创建和运行 ThreadUtil
从[Oracle官方文档](https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.State.html)中我们知道Java线程有如下几种状态
NEW : Thread对象已经创建出来但是还没有运行.
RUNNABLE : 线程正在执行.
BLOCKED : 线程等待锁
WAITING : 线程正在等待另一个线程来对自己执行某个特定的行为.
TIMED_WAITING: 线程正在等待(在超时范围内)另一个线程来对自己执行某个特定的行为.
TERMINATED : 线程退出.
从google上找了俩张线程图
我们重点看一下BLOCKED, WAITING, TIMED_WAITING
BLOCKED 当等待锁的时候,会引发线程的等待状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class TestLock { private static final Object lock = new Object (); public static void main (String[] args) { ThreadUtil.printThreadState("thread1" , "thread2" ); Runnable runnable = () -> { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " Sleep" ); long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 5000 ) { break ; } } System.out.println(Thread.currentThread().getName() + " Sleep Finshed" ); } }; Thread thread1 = new Thread (runnable, "thread1" ); Thread thread2 = new Thread (runnable, "thread2" ); thread1.start(); thread2.start(); } }
结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 thread1 Sleep 2016-09-22T17:05:37.064 thread2 -> BLOCKED 2016-09-22T17:05:37.064 thread1 -> RUNNABLE 2016-09-22T17:05:38.029 thread2 -> BLOCKED 2016-09-22T17:05:38.029 thread1 -> RUNNABLE 2016-09-22T17:05:39.030 thread2 -> BLOCKED 2016-09-22T17:05:39.030 thread1 -> RUNNABLE 2016-09-22T17:05:40.031 thread2 -> BLOCKED 2016-09-22T17:05:40.031 thread1 -> RUNNABLE thread1 Sleep Finshed thread2 Sleep 2016-09-22T17:05:41.032 thread2 -> RUNNABLE 2016-09-22T17:05:42.033 thread2 -> RUNNABLE 2016-09-22T17:05:43.034 thread2 -> RUNNABLE 2016-09-22T17:05:44.035 thread2 -> RUNNABLE 2016-09-22T17:05:45.037 thread2 -> RUNNABLE thread2 Sleep Finshed
我们看到thread2就进入了BLOCKED状态.
WAITING 调用下面三个方法,线程会进入WAITING状态
Object.wait with no timeout
Thread.join with no timeout
LockSupport.park
注意在调用 Object.wait 和 Thread.join 方法时, 不能传参, 否则线程不会进入到WAITING状态, 我在join中做了个实现
wait 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class TestWait { private static final Object lock = new Object (); public static void main (String[] args) throws InterruptedException { ThreadUtil.printThreadState("User" ); Thread thread = new Thread (() -> { long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 2000 ) { break ; } } synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "User" ); thread.start(); Thread notify = new Thread (() -> { long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 5000 ) { break ; } } synchronized (lock) { lock.notify(); } }, "notify" ); notify.start(); } }
结果为
1 2 3 4 5 2016 -09-22T17:18 :12.745 User -> RUNNABLE2016 -09-22T17:18 :13.747 User -> WAITING2016 -09-22T17:18 :14.729 User -> WAITING2016 -09-22T17:18 :15.712 User -> WAITING2016 -09-22T17:18 :16.713 User -> WAITING
join Threead类的join()方法被调用时,调用它的线程将被挂起,直到这个线程对象完成它的任务join(long millseconds)如果使用这种方法,被挂起的线程只要满足指定的毫秒数到,或者join线程运行完,被挂起线程恢复运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.time.LocalDateTime;public class TestJoin { public static void main (String[] args) throws InterruptedException { ThreadUtil.printThreadState("main" , "car" , "dog" ); Thread carThread = new Thread (() -> { System.out.println(LocalDateTime.now() + " Car run" ); long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 3000 ) { break ; } } System.out.println(LocalDateTime.now() + " Car Stop" ); }, "car" ); Thread dogThread = new Thread (() -> { System.out.println(LocalDateTime.now() + " Dog run" ); long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 3000 ) { break ; } } System.out.println(LocalDateTime.now() + " Dog Stop" ); }, "dog" ); try { dogThread.start(); carThread.start(); System.out.println("Begin join" ); carThread.join(); System.out.println("Started join" ); } catch (Exception e) { e.printStackTrace(); } } }
结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Begin join 2016-09-22T17:17:04.053 Car run 2016-09-22T17:17:04.053 Dog run 2016-09-22T17:17:05.011 car -> RUNNABLE 2016-09-22T17:17:05.011 main -> WAITING 2016-09-22T17:17:05.011 dog -> RUNNABLE 2016-09-22T17:17:06.013 car -> RUNNABLE 2016-09-22T17:17:06.013 main -> WAITING 2016-09-22T17:17:06.013 dog -> RUNNABLE 2016-09-22T17:17:07.011 car -> RUNNABLE 2016-09-22T17:17:07.011 main -> WAITING 2016-09-22T17:17:07.011 dog -> RUNNABLE 2016-09-22T17:17:07.055 Car Stop Started join 2016-09-22T17:17:07.060 Dog Stop
当我调用carThread.join(3);结果为
1 2 3 4 5 6 7 8 9 10 11 12 Begin join Started join 2016-09-22T17:19:26.029 Car run 2016-09-22T17:19:26.036 Dog run 2016-09-22T17:19:27.004 dog -> RUNNABLE 2016-09-22T17:19:27.005 car -> RUNNABLE 2016-09-22T17:19:28.004 dog -> RUNNABLE 2016-09-22T17:19:28.004 car -> RUNNABLE 2016-09-22T17:19:29.005 dog -> RUNNABLE 2016-09-22T17:19:29.005 car -> RUNNABLE 2016-09-22T17:19:29.030 Car Stop 2016-09-22T17:19:29.037 Dog Stop
TIMED_WAITING 调用下列方法线程会进入TIMED_WAITING状态
Thread.sleep
Object.wait with timeout
Thread.join with timeout
LockSupport.parkNanos
LockSupport.parkUntil
sleep 使用sleep()方法中断线程的运行. sleep()中断线程后,直到CPU时钟来临JVM选中它继续执行的这段期间, 该线程不会占用任何资源
yield()方法通知JVM该线程对象可以释放CPU了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.concurrent.TimeUnit;public class TestSleep { public static void main (String[] args) { ThreadUtil.printThreadState("User" ); Thread thread = new Thread (() -> { long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 2000 ) { break ; } } System.out.println("User Sleep" ); try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("User Sleep Finshed" ); }, "User" ); thread.start(); } }
结果为
1 2 3 4 5 6 2016-09-22T17:29:12.378 User -> RUNNABLE 2016-09-22T17:29:13.345 User -> RUNNABLE User Sleep 2016-09-22T17:29:14.346 User -> TIMED_WAITING 2016-09-22T17:29:15.347 User -> TIMED_WAITING User Sleep Finshed
join 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.time.LocalDateTime;public class TestJoin { public static void main (String[] args) throws InterruptedException { ThreadUtil.printThreadState("main" , "car" , "dog" ); Thread carThread = new Thread (() -> { System.out.println(LocalDateTime.now() + " Car run" ); long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 3000 ) { break ; } } System.out.println(LocalDateTime.now() + " Car Stop" ); }, "car" ); Thread dogThread = new Thread (() -> { System.out.println(LocalDateTime.now() + " Dog run" ); long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 3000 ) { break ; } } System.out.println(LocalDateTime.now() + " Dog Stop" ); }, "dog" ); try { dogThread.start(); carThread.start(); System.out.println("Begin join" ); carThread.join(3000 ); System.out.println("end join" ); } catch (Exception e) { e.printStackTrace(); } } }
结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Begin join 2016-09-22T18:23:56.591 Dog run 2016-09-22T18:23:56.601 Car run 2016-09-22T18:23:57.646 main -> TIMED_WAITING 2016-09-22T18:23:57.647 dog -> RUNNABLE 2016-09-22T18:23:57.647 car -> RUNNABLE 2016-09-22T18:23:58.582 main -> TIMED_WAITING 2016-09-22T18:23:58.582 dog -> RUNNABLE 2016-09-22T18:23:58.582 car -> RUNNABLE end join 2016-09-22T18:23:59.583 dog -> RUNNABLE 2016-09-22T18:23:59.583 car -> RUNNABLE 2016-09-22T18:23:59.592 Dog Stop 2016-09-22T18:23:59.602 Car Stop
wait 参考join
守护线程的创建和运行 守护线程的优先级很低,通常来说,同一个应用程序中没有其他的线程运行,守护线程才运行. 当守护线程运行结束后,JVM也就结束了这个应用程序
守护线程通常用来作为同一程序中普通线程的服务提供者,因为没有办法确定守护线程什么时候才能获取CPU时钟, 而且在没有其他线程运行的时候,守护线程随时可能会结束
一个典型的守护线程就是java的垃圾回收器
setDeamon()方法只能在start()方法之前被调用,一旦线程开始运行,将不能再修改其状态
注: 需要注意的是,只有在没有用户线程运行的时候,而不是没有用户线程存在的时候守护线程才运行. 例如当所有用户线程多沉睡后,也会被视为没有用户线程执行
Thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
在Daemon线程中产生的新线程也是Daemon的
不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。因为在Daemon Thread还没来的及进行操作时,虚拟机可能已经退出了。
当用户线程都运行完后,守护线程也就跟着结束了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class Main { public static void main (String[] args) { DeameanThread dt = new DeameanThread (); NormalThread nt = new NormalThread (); nt.start(); dt.start(); System.out.println("main" ); } } class NormalThread extends Thread { NormalThread() { setDaemon(false ); } @Override public void run () { long old = System.currentTimeMillis(); while ((System.currentTimeMillis() - old) < 3000 ) {} System.out.println("NormalThread" ); } } class DeameanThread extends Thread { DeameanThread() { setDaemon(true ); } @Override public void run () { while (true ){} } }
ThreadUtil 在上面的例子中用到的输出线程状态信息的工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.time.LocalDateTime;public class ThreadUtil { public static void printThreadState (String... filter) { Thread print = new Thread (() -> { long now = System.currentTimeMillis(); while (true ) { if (System.currentTimeMillis() - now > 1000 ) { now = System.currentTimeMillis(); Thread.getAllStackTraces().forEach((key, thread) -> { for (int i = 0 ; i < filter.length; i++) { if (key.getName().equals(filter[i])) { System.out.println(LocalDateTime.now() + " " +key.getName() + " -> " + key.getState()); } } }); } } }, "Print" ); print.start(); } }