多线程——线程的生命周期

Java中,线程从创建到结束,共分为5个状态。一个线程在其生命周期内,总是处于某种状态:

  • 创建状态
  • 可运行状态
  • 不可运行状态
  • 死亡状态

一、创建状态

执行下列语句时,线程就处于创建状态:
       Thread myThread = new MyThreadClass( );

当一个线程处于创建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。

二、可运行状态

Thread myThread = new MyThreadClass( );
       myThread.start( );
      当一个线程处于可运行状态时,系统为这个线程分配了它需的系统资源,安排其运行并调用线程运行方法,这样就使得该线程处于可运行   ( Runnable )状态。

注意:

这一状态并不是运行中状态(Running ),因为线程也许实际上并未真正运行。单处理器的计算机要在同一时刻运行所有的处于可运行状态的线程是不可能的,Java的运行系统必须实现调度来保证这些线程共享处理器。

三、不可运行状态

当下面5种情况发生时,线程就进入不可运行状态:

(1) 调用了sleep()方法;

(2) 调用了suspend()方法;

(3) 为等候一个条件变量,线程调用wait()方法;

(4) 输入输出流中发生线程阻塞。

(5)线程试图调用另一个对象的“同步”方法,但那个对象处于对象锁定状态,暂时无法使用

上面5种情况,要使线程返回可运行状态,各有特定的方法与之对应:

1) 如果线程处于睡眠状态中,sleep()方法中的参数为睡眠时间,当这个时间过去后,线程即为可运行的;

2) 如果一个线程被挂起,要使该线程重新处于可运行状态,需调用resume()方法;

3) 如果线程在等待条件变量,那么要停止等待的话,需要该条件变量的线程对象调用notifyAll()方法;

4) 如果在I/O流中发生线程阻塞,则特定的I/O完成后可结束这种不可运行状态。

5) 同步的方法完成,释放了同步锁

四、死亡状态

线程的终止一般可通过两种方法实现:

(1)自然撤消

(2)调用stop()方法停止当前线程

总结: 线程的生命周期、运行状态和转换:

image

五、决定线程生命周期的相关方法:

1)、join方法:

         t.join( )方法使当前的线程等待,直到 t 结束为止,线程恢复到运行(runnable)状态

三种调用格式:

①join():如当前线程发出调用t.join(),则当前线程将等待线程 t结束后在继续执行。

②join(long millis):如当前线程发出调用t.join(),则当前线程将等待线程t结束或最多等待mills毫秒后在继续执行。

③join(long millis,long nanos) throws InterruptedException

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
42
43
44
 
package com.model.elgin.thread;

public class TestThread1 {
   
   
public static void main(String[] args)  {
         MyThread mt1=
new MyThread();
         MyThread1 mt2=
new MyThread1();
        
//setName方法为线程命名
         mt1.setName("mt1");
         mt2.setName(
"mt2");;
        
//start方法开启线程
         mt1.start(); 
        
/*try {
            mt1.join();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }*/

         mt2.start();
    }
        
}
    
class MyThread extends Thread{
    
    @Override
   
public void run() {
       
for (int i = 0; i < 10; i++) {
           
//currentThread()为Thread类的静态方法,作用是得到当前正在运行的线程 
            System.out.println(Thread.currentThread().getName() + ": Hello thread1-" + i);
        }
    }
    
}

class MyThread1 extends Thread{
    
    @Override
   
public void run() {
       
for (int i = 0; i < 10; i++) {
           
//currentThread()为Thread类的静态方法,作用是得到当前正在运行的线程 
            System.out.println(Thread.currentThread().getName() + ": Hello thread2-" + i);
        }
    }   
}

加入join方法和未加入join方法(上述代码13-17行)运行结果比较:

可以看出加入join方法之后,先执行完mt1线程再去执行mt2.而未加入的时候则无规律。

image   image

2)、interrupt()方法:中断线程

如果一个线程t在调用sleep()、join()、wait()等方法被阻塞时,则t.interrupt()方法将中断t的阻塞状态,并将接收到InterruptException对象。

3)、isDaemon()和setDaemon()方法

  • 线程可分为守护线程与用户线程
  • 当一个程序中只有一个守护线程在运行,程序会立即退出;如果一个程序还有正在运行的用户线程,该程序不会中止。
  • 判断一个线程是用户线程还是守护线程,用isDaemon()方法
  • 将一个线程设置为守护线程用setDaemon()方法

4)、结束线程

  • 线程完成运行并结束后,将不能再运行。
  • 除正常运行结束外,还可用其他方法控制使其停止。
    •   用stop( )方法,已过时

                           强行终止线程,容易造成线程的不一致。

    • 使用标志flag。

                         通过设置flag 指明run( )方法应该结束。

示例:

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
 
package com.model.elgin.thread;

public class TestThread3 {
   
public static void main(String[] args) {
        StopThread st=
new StopThread();
        Thread t=
new Thread(st);
        System.out.println(
"say hello start...");
        t.setPriority(Thread.MAX_PRIORITY);
        t.start();
        System.out.println(
"stop say hello...");
        st.stopSayHello();
    }
}

class StopThread implements Runnable{
    
       
private boolean flag=false;
       
int i=0;
       
public void run() {
           
while(!flag){
                System.out.println(
"Hello"+i++);
            }
        }
        
       
public void stopSayHello(){
           
this.flag=true;
        }   
}
原文地址:https://www.cnblogs.com/elgin-seth/p/5293718.html