Java终止线程有哪几种方式?那终止进程呢?

在讨论线程终止的方式前,我们先讨论一个问题,线程和进程有什么区别?

简而言之,进程是程序运行和资源分配的基本单位,而线程是CPU调度的基本单元,一个程序至少有一个进程,一个进程至少包含一个线程(一个进程可以包含多个线程),简单来说,线程是进程当中的一条执行流程。所以,同一个进程内,多个线程之间可以共享数据和资源,减少切换次数(并发),从而效率更高,但是由于每个线程都有一套独立的寄存器和栈,所以线程的控制流是相对独立的。

如何理解上面这句减少切换次数?举个例子,你要做一道菜:做一个番茄鸡蛋葱花汤,那么,是不是可以在热汤的过程中,打鸡蛋进行搅拌呢?这个过程中,你还可以做点其他的东西?谁会傻傻的等在锅边?什么?你不知道这道菜的流程?

好吧,我先说下如何做这道菜吧,烧热水,烫一下洗净的番茄,对番茄进行剥皮,然后切成细块,锅里烧油,油温八成热,倒入番茄,加盐炒(不加盐番茄炒不成汁),待番茄炒成番茄汁,加入凉水,大伙烧,然后碗中打入几个蛋,放入一点点盐,一点点白醋,搅拌均匀,待锅中水热,取一双筷子,碗口对准筷子,筷子立于锅中,将鸡蛋均匀倒入锅中,1至2分钟以后,撒入洗净切好的葱花即可。

第一次烧热水的时候,你会傻傻的等着吗?肯定不会吧,这个时候可以洗好葱花,洗好番茄,并将葱花切好,如果可以的话,你甚至可以将蛋也打了。这样的话,第二次烧热水的时候,你甚至可以刷刷技术博客,做个好学的孩子。这个就是CPU管理多个进程的初步想法:交替执行。并且,CPU可以在进程间切换,比如你在做菜的时候,突然想喝杯红酒,你就可以在空隙时间喝哟。

那么,如何理解进程和线程的关系呢?
1)一个进程中可以同时存在多个线程;
2)并且各个线程之间可以并发执行;
3)各个线程之间可以共享数据和资源等;
4)一个进程中的一个线程挂了,会导致该进程中的所有线程都挂了。

比如做番茄鸡蛋葱花汤的时候,一旦番茄搞没了,或者鸡蛋不小心把蛋壳丢碗里,鸡蛋丢垃圾桶里,其他线程就气死了,这个番茄鸡蛋葱花汤就凉凉了。

线程有哪些状态?
线程通常都有五种状态,新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)。
1、新建状态:当程序使用new关键字创建了一个线程对象后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值,在未调用该对象的start方法之前,线程都处于新建状态。

2、就绪状态:当线程对象调用了start()方法之后,该线程就进入了就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行。但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。

3、运行状态:如果处于就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态;也就是线程调度程序将处于就绪状态的线程设置为当前线程,开始运行run函数当中的代码。

4、阻塞状态:线程正在运行的时候,被暂停,通常可以理解为指线程因为某种原因放弃了cpu使用权,sleep,suspend,wait等方法都可以导致线程阻塞。阻塞的情况分3种,分别是等待阻塞、同步阻塞和其他阻塞。

5、死亡状态:如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。

Java中终止线程有哪几种方式?

1、正常运行结束:如果面试问到这个问题,一般人都会想不到有一种方式可以正常终止线程,那就是正常运行结束。

2、使用退出标志退出线程:使用退出标识,使得线程正常退出,即当run方法完成后进程终止。

/**
 * 使用退出标志结束线程
 */
public class UseOutSignEndThreadTest extends Thread {
	 
	public static boolean exit = true;
 
	// 重写run方法,run方法的方法体就是现场执行体
	public void run() {
		while (!exit) {
			System.out.println("线程终止!");
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("结束!");
			break;
		}
	}
 
	public static void main(String[] args) {
		exit = false;
		new UseOutSignEndThreadTest().start();
	}
 
}

3、使用interrupt方法中断线程

需要注意的是:interrupt()方法不像stop方法强行终止一个线程,它只是把要被停止的线程设置成中断状态,而此时要被中断的线程是可以继续执行的。

/**
 * 使用interrupt()结束线程
 */
public class UseInterruptEndThreadTest extends Thread {
	
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 4; i++) {
			if (this.isInterrupted()) {
				System.out.println("线程已经结束!");
				break;
			}
			System.out.println("i=" + (i + 1));
		}
		System.out.println("我要证明线程未真正结束!");

	}

	public static void main(String[] args) {
		try {
			UseInterruptEndThreadTest thTest = new UseInterruptEndThreadTest();
			thTest.start();
			Thread.sleep(20);
			thTest.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}


程序执行结果:
i=1
i=2
i=3
i=4
我要证明线程未真正结束!

所以,使用interrupt()方法来中断线程需要考虑两种情况:

1)线程处于阻塞状态:如使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态,从而让我们有机会结束这个线程的执行。这种方法也叫做抛异常法。

/**
 * 使用interrupt()结束线程 但是线程处于阻塞状态
 */
public class UseInterruptEndThreadAndThreadInBlockedTest extends Thread {

	@Override
	public void run() {
		super.run();
		try {
			for (int i = 0; i < 1000; i++) {
				if (this.isInterrupted()) {
					System.out.println("线程已经结束!");
					// 改动break为抛出异常(抛异常法)
					throw new InterruptedException();
				}
				System.out.println("i=" + (i + 1));
			}

			System.out.println("我想证明抛异常的时候线程已经结束了,可惜没办法输出!");
		} catch (InterruptedException e) {
			System.out.println("捕获InterruptedException异常");
			e.printStackTrace();
		}
		System.out.println("我要证明我是否还活着");

	}

	public static void main(String[] args) {
		try {
			UseInterruptEndThreadAndThreadInBlockedTest thTest = new UseInterruptEndThreadAndThreadInBlockedTest();
			thTest.start();
			Thread.sleep(20);
			thTest.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

循环中设置的数值越大,效果越明显。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的,一定要先捕获InterruptedException 异常之后通过break来跳出循环,才能正常结束run方法。

2)线程未处于阻塞状态:使用isInterrupted()判断线程的中断标志来退出循环。当使用interrupt()方法时,中断标志就会置true,和使用自定义的标志来控制循环是一样的道理。

isInterrupted()和interrupted()方法有什么区别?

isInterrupted()判断的是调用它的对象所启动的线程是否处于中断状态,而不是判断当前线程。

interrupted()方法是静态方法,它判断的是当前线程是否中断

/**
 * 使用isInterrupt()
 */
public class UseIsInterruptEndThreadTest extends Thread {

	@Override
	public void run() {
		super.run();
		try {
			for (int i = 0; i < 1000; i++) {
				if (this.isInterrupted()) {
					System.out.println("线程已经结束!");
					// 改动break为抛出异常(抛异常法)
					throw new InterruptedException();
				}
				System.out.println("i=" + (i + 1));
			}
 
			System.out.println("我想证明抛异常的时候线程已经结束了,可惜没办法输出!");
		} catch (InterruptedException e) {
			System.out.println("捕获InterruptedException异常");
			e.printStackTrace();
		}
		System.out.println("我要证明我是否还活着");
 
	}
 
	public static void main(String[] args) {
		try {
			UseIsInterruptEndThreadTest thTest = new UseIsInterruptEndThreadTest();
			thTest.start();
			Thread.sleep(20);
			thTest.interrupt();
//			System.out.println("1interrupted thread is stop=" + thTest.interrupted()); //false
//			System.out.println("2interrupted thread is stop=" + thTest.interrupted()); //false
			System.out.println("1isInterrupted thread is stop=" + thTest.isInterrupted()); //true
			System.out.println("2isInterrupted thread is stop=" + thTest.isInterrupted()); //true
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}

那么,如何终止进程呢?

1)正常结束。进程正常执行结束,不就终止了么?
2)异常结束。机器崩了,进程跑不动,也就死了。
3)外界干预。进程正欢呼雀语呢,一个kill,死了。
 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值