Java并发编程之线程生命周期、守护线程、优先级和join、sleep、yield

Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法、线程沟通方法的灵活运用。这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一。

Java线程的生命周期

Java线程类定义了New、Runnable、Running Man、Blocked和Dead五种状态。

New

当初始化了一个线程对象之后,线程就进入了New的状态。此时JVM会为其分配内存、初始化成员变量的值,跟一般的对象一样。

Runnable

当调用线程对象的start方法之后,就进入Runnable状态。JVM会为其创建虚拟机栈程序计数器。此时仅表面线程可以开始运行,但何时运行取决于JVM的线程调度器。

Running

当线程获取到CPU资源的时候,就进入Running状态执行线程方法了。如果线程数大于多处理器的数目,会存在多个线程轮换,尽管多个处理器会同时并行处理几个线程。

线程调度的细节取决于底层平台,当Running的线程调用其yield方法或失去CPU资源的时候,即回到Runnable状态

Blocked

当发生如下情况,线程会被阻塞/重新进入Runnable状态:

1. 线程调用sleep方法                ===>    sleep方法经过指定时间

2. 线程调用了一个阻塞式IO              ===>    调用的阻塞式IO方法返回 

3. 试图获取一个正被使用的同步锁           ===>    成功获取同步锁

4. 等待notify                     ===>    其它线程发出了notify

5. 线程调用suspend方法(容易导致死锁,不建议使用) ===>     被调用了resume方法

Dead

当发生如下情况,线程结束

1. 线程执行体完成

2. 抛出未捕获的异常或错误

3. 直接调用stop方法(容易导致死锁,不建议使用)

可通过调用线程对象的isAlive方法,如果处于新建和死亡状态会返回false

线程管理

常用的线程管理包括设置后台线程、设置优先级、join、sleep和yield

设置后台线程

setDaemon(true):设置为后台线程

isDaemon():用于判断指定线程是否为后台线程

设置优先级

setPriority(int priority):设置优先级

getPriority():获取优先级

 1 public class ThreadPriority {
 2 
 3     public static void main(String[] args) {
 4         Thread t1 = new Thread(()->
 5         {
 6             while(true) {
 7                 System.out.println("t11111");
 8             }
 9         }, "t1");
10         t1.setPriority(Thread.NORM_PRIORITY);
11         
12         Thread t2 = new Thread(()->{
13             while (true) {
14                 System.out.println("t22222");
15             }
16         });
17         t2.setPriority(10);
18 
19         t1.start();
20         t2.start();
21     }
22 
23 }
View Code

join

join线程可以理解为把一个问题分为若干小问题由不同的线程处理,其它线程处理过程中,调用join方法的线程处于阻塞状态,在其它线程处理完毕后,再回到运行状态的概念。

 1 public class ThreadJoin {
 2     
 3     private static void shortSleep() {
 4         try {
 5             TimeUnit.SECONDS.sleep(1);
 6         } catch (InterruptedException e) {
 7             e.printStackTrace();
 8         }
 9     }
10     
11     private static Thread create(int seq) {
12         return new Thread(() -> {
13             for (int i = 0; i < 10; i++) {
14                 System.out.println(Thread.currentThread().getName() + "#" + i);
15                 shortSleep();
16             }
17         }, String.valueOf(seq));
18     }
19 
20     public static void main(String[] args) throws InterruptedException {
21         
22         List<Thread> threads = IntStream.range(1, 3).mapToObj(ThreadJoin::create).collect(Collectors.toList());
23         
24         threads.forEach(Thread::start);
25         //main线程调用join方法, 会进入阻塞, 等其它线程完成了再行继续
26         for(Thread thread : threads) {
27             thread.join();
28         }
29         
30         for(int i = 0; i < 10; i++) {
31             System.out.println(Thread.currentThread().getName() + "#" + i);
32             shortSleep();
33         }
34     }
35 }
View Code

sleep

Thread类的静态方法,用于暂停线程的执行。一般建议使用1.5后新增的TimeUnit类来更好的暂停线程

 1 public class ThreadSleep {
 2     
 3     private static void sleep(int ms) {
 4         try {
 5             TimeUnit.SECONDS.sleep(ms);
 6         } catch (InterruptedException e) {
 7             e.printStackTrace();
 8         }
 9     }
10 
11     public static void main(String[] args) {
12 
13         new Thread(() -> 
14         {
15             long startTime = System.currentTimeMillis();
16             sleep(2);
17             long endTime = System.currentTimeMillis();
18             System.out.println(String.format("Total spend %d second", (endTime - startTime)));
19         }).start();
20         
21         /*
22          * Thread sleep times depends on your system
23          */
24         long startTime = System.currentTimeMillis();
25         sleep(3);
26         long endTime = System.currentTimeMillis();
27         System.out.println(String.format("Main thread total spend %d second", (endTime - startTime)));
28         
29     }
30 }
View Code

yield

与sleep方法不同,yield方法只是让当前线程暂停一下,以便线程调度器操作线程调度。该方法不会让线程进入阻塞

 1 public class ThreadYield {
 2     
 3     private static Thread create(int index) {
 4         try {
 5             TimeUnit.SECONDS.sleep(1);
 6         } catch (InterruptedException e) {
 7             e.printStackTrace();
 8         }
 9         return new Thread(()->
10         {
11             if (index == 0) {
12                 Thread.yield();
13             }
14             System.out.println(index);
15         });
16     }
17 
18     public static void main(String[] args) {
19         IntStream.range(0, 2).mapToObj(ThreadYield::create).forEach(Thread::start);
20     }
21 }
View Code

猜你喜欢

转载自www.cnblogs.com/leoliu168/p/9914393.html