线程生命周期

Posted python-data-machine

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程生命周期相关的知识,希望对你有一定的参考价值。

线程的生命周期:一个线程从创建到消亡的过程

如下图,表示线程生命周期中的各个状态:

线程的生命周期可以分为五个状态:

1.创建状态:

  当用new操作符创建一个新的线程对象时,该线程处于创建状态。

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

2.可运行状态【runnable】:

  执行线程的start()方法将为线程分配必须的系统资源,安排其运行,并调用线程体——run()方法,

  这样就使得该线程处于可运行状态(Runnable)。

  这一状态并不是运行中状态(Running),因为线程也许实际上并未真正运行。

       注意:一个线程只有在start()之后才是具备可执行能力的(runnable状态的),但是具备可执行能力

     并不代表着会立即执行(running)一个线程,线程会等待着cpu的调度,只有在cpu调度了该

                  线程之后,该线程才会执行!换句话说:runnable状态的线程可能会立即执行,也可能不会

                  立即执行,只有当runnable状态的线程获得cpu调度执行权的时候才会立即执行!

3.正在执行状态【running】:

  需要注意的是:线程是被cpu调度的,多个线程或者多个进程之间的切换是由cpu来完成的!

4.阻塞状态:

  当发生下列事件时,处于运行状态的线程会转入到不可运行状态【阻塞状态】:

  调用了sleep()方法;

  线程调用wait()方法等待特定条件的满足;

  线程输入/输出阻塞。

  或者线程在抢锁的时候

  执行了yield()方法

  返回可运行状态:

  处于睡眠状态的线程在指定的时间过去后;

  如果线程在等待某一条件,另一个对象必须通过notify()或notifyAll()方法通知等待线程条件的改变;

  如果线程是因为输入输出阻塞,等待输入输出完成。

注意:1.当我们调用Thread.sleep()方法、wait()方法、yield()方法,也或者是争抢锁资源的时候 线程就会由running状态转到blocked【阻

    塞状态】,而一个线程进入阻塞【blocked】, 状态之后,是不能直接恢复到running状态的,它是需要先进入!

           2.另外running状态的线程除了可以通过blocked状态进入runnnable状态的情况外,处于running状态的线程还可以直接进入到runnable

    状态,这是因为cpu调度将执行权交给了其它线程了,多个线程或者多个进程之间的切换是由cpu来完成的!只不过速度很快,你看

    不出来而已,但是在某一个具体的时间点cpu只能执行一个线程!

5.消亡状态:

  当线程的run()方法执行结束后,该线程自然消亡。

   注意:最后一个状态是终结状态[disabled或者terminated]:当线程正常执行完毕或者也可能是从blocked状态的线程被打断的时候【比如

      sleep()、wait()、抢锁的时候被打断了】就会进入这种终结状态,也有可能由于操作系统的原因,线程会直接从runnable状态进入

      到terminated状态!

 

public class MultiThread {
	public static void main(String[] args) {
		new Thread("READ-THREAD"){
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				readFromDataBase();
			}
		}.start();
		new Thread("WRITE-THREAD"){
			@Override
			public void run() {
				writeDataToFile();
			}
		}.start();
	}
	
	private static void readFromDataBase() {
		//read data from database and handle it
		try {
			println("begin read data from db.");
			Thread.sleep(1000*30L);
			println("read data done and handle it now");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		println("the data handle finish and successfully.");
	}
	
	private static void writeDataToFile(){
		//write data to file
		try {
			println("begin write data to file.");
			Thread.sleep(1000*30L);
			println("write data done and start handle it now");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		println("the data handle finish and successfully.");
	}
	private static void println(String message){
		System.out.println(message);
	}
	
}

 针对上面的代码,这里需要注意的是我们直接用匿名类对象直接调用的是start()方法,然后JVM虚拟机就会帮我们调用线程的run()方法,所以才会在

System.out.println(Thread.currentThread().getName());这段代码这里输出了READ-THREAD !如果我们不是用匿名对象,而是创建一个普通的对象,然后用
普通对象直接调用run()方法,也就如下:
		Thread t = new Thread("READ-THREAD"){
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				readFromDataBase();
			}
		};
		//t.start()
		t.run();

 显然这是不可以的,因为如果我们直接用线程对象调用run()方法,而不是调用start()方法,那么此时该线程就相当于没启动,此时

    System.out.println(Thread.currentThread().getName());输出的将不再是READ-THREAD,而是main线程了!切记切记!

 

 

另外,我们这里也总结一下其它的:

1.我们知道,进程中包括线程,线程才是真正干事的,也就是说一个进程中至少有一个线程(main线程或者主线程),这个线程是被JVM调用的,而且线程的名字就是main!

2.实现一个线程,必须创建Thread实例,覆写里面的run方法,并且调用start()方法!这里需要注意:如果我们不调用run方法,那么这个类就是一个普通的实例类,不是多线程!

3.当调用了一个线程的start()方法之后,此时至少存在两个线程,一个是调用线程的main线程【也就是调用线程的线程】,再一个是这个线程!

4.线程的生命周期分为:new ,runnable,running,block,terminate等几部分!

 

以上是关于线程生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Android片段生命周期:onResume调用了两次

在不存在的片段上调用片段生命周期和 onCreate 的问题

导航上的片段生命周期重叠

Android 片段生命周期

关于片段生命周期,何时调用片段的 onActivityResult?

理解片段事务期间片段的生命周期方法调用