【Java 语言】Java 多线程 一 ( 线程启动 | 线程中断 )

一. 线程启动

线程启动 :

-- 1. 继承 Thread 运行线程 : 重写 Thread 类的 run 方法, 然后执行该线程;

-- 2. 实现 Runnable 接口, 并运行线程;

-- 代码示例 :

package com.hanshuliang.thread;

public class ThreadStart {

	public static void main(String[] args) {
		//1. 继承 Thread 运行线程
		MyThread thread = new MyThread();
		thread.start();

		//2. 实现 Runnable 接口, 并运行线程
		Thread runnableThread = new Thread(new MyRunnable());
		runnableThread.start();
	}

	//1. 继承 Thread 类
	static class MyThread extends Thread{
		@Override
		public void run() {
			super.run();
			System.out.println("MyThread 线程启动");
		}
	}

	//2. 实现 Runnable 接口
	static class MyRunnable implements Runnable{
		@Override
		public void run() {
			System.out.println("MyRunnable 线程启动");
		}
	}
}

-- 运行结果 :

MyThread 线程启动
MyRunnable 线程启动

三. 线程停止

线程停止常用方法 :

-- 1. 使用 interrupt() 方法停止线程;

-- 2. 使用退出标志, 让线程正常退出;

-- 3. 弃用的方法 (不推荐) : 使用 stop() 方法强制停止线程, 但是该方法已经作废, 不建议使用;

1. 使用 interrupt() 方法停止线程


(1) 线程无法立即停止

interrupt() 使用说明 :

-- 打标记 : 调用该方法, 不能马上停止该线程, 只是在当前线程打了一个停止标记;

代码示例 :

-- 代码 :

public class InterruptDemo {
	public static class MyThread extends Thread {
		@Override
		public void run() {
			super.run();
			for (int i = 1; i <= 1000000; i++)	//打印 一百万 数字, 大概持续 5 ~ 10 秒左右
				System.out.println(i);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();
		thread.start();						//启动线程
		Thread.sleep(100);					//启动线程 100ms 后中断线程
		thread.interrupt();					//中断线程
	}
}

-- 运行结果 : 这里只贴上最后几行 命令行的运行结果;

... ...
999996
999997
999998
999999
1000000

-- 总结 : 在上述程序中, 打印了 100 万数字, 从 1 到 100 0000, 整个过程持续了 10秒左右, 但是我们在 线程开始后 100ms 就中断了线程, 但是线程还是执行完毕了, 说明线程并没有在调用 interrupt() 方法后立即停止;

(2) 线程停止状态判定

两个线程停止状态判定的方法 :

-- 1. interrupted() 方法 : ①判断当前线程的中断标志, ②如果是中断标志 true, 那么清除中断标志, 改为 false;,③ 连续两次调用该方法, 第二次返回 false, ④ 静态方法 : 该方法是测试当前线程的中断标志, 在哪个线程中调用, 就是判定的哪个线程的中断标志, 不管调用的主体是哪个线程;

-- 2. isInterrupted() 方法 : 判断线程的 中断状态, 不管真实的运行状态, 只关心状态;

-- 注意 : 两个方法都是判断 中断状态的, 与线程的真实运行状况无关;

(3) interrupted() 方法测试

interrupted () 方法测试1 : 测试 interrupted 方法的判断是否已经中断的效果;

-- 测试代码 :

public class InterruptedDemo1 {
	public static class MyThread extends Thread {
		@Override
		public void run() {
			super.run();
			for (int i = 1; i <= 10; i++)	//打印10个数字
				System.out.println(i);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();
		thread.start();						//启动线程
		thread.interrupt();					//启动线程后马上 中断线程

		System.out.println("第一次 : thread.interrupted() = " + thread.interrupted());
		System.out.println("第二次 : thread.interrupted() = " + thread.interrupted());
	}
}

-- 执行结果 :

第一次 : thread.interrupted() = false
1
2
第二次 : thread.interrupted() = false
3
4
5
6
7
8
9
10

-- 总结 : 启动线程后, 立即调用 interrupt 方法 中断线程, 但是 在主线程中 调用 thread.Interrupted() 方法, 打印出来的是 主线程的中断状态标志, 虽然是调用的 thread 子线程的对象的方法, 但是该方法是一个静态方法, 在哪个线程调用, 就是打印哪个线程的中断标志;

interrupted () 方法测试2 : 测试 interrupted 方法的 清除 中断状态 的效果;

-- 1. 测试代码 :

public class InterruptedDemo {
	public static void main(String[] args) throws InterruptedException {
		Thread.currentThread().interrupt(); 	//中断主线程

		System.out.println("第一次 : thread.interrupted() = " + Thread.interrupted());
		System.out.println("第二次 : thread.interrupted() = " + Thread.interrupted());
	}
}

-- 2. 执行结果 :

第一次 : thread.interrupted() = true
第二次 : thread.interrupted() = false

-- 3. 总结 : 使用 interrupted() 方法, 如果当前线程的状态是中断状态, 即返回了 true, 那么需要清除该标志, 下一次调用 interrupted() 方法后, 返回值就是 false 了;

(4) isInterrupted() 方法测试

isInterrupted() 方法测试1 : 测试其 中断状态, 与上面的 interrupted() 方法对比;

-- 1. 测试代码 :

public class IsInterruptedDemo {
	public static class MyThread extends Thread {
		@Override
		public void run() {
			super.run();
			for (int i = 1; i <= 10; i++)	//打印10个数字
				System.out.println(i);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();
		thread.start();						//启动线程
		thread.interrupt();					//启动线程后马上 中断线程

		System.out.println("第一次 : thread.interrupted() = " + thread.isInterrupted());
		System.out.println("第二次 : thread.interrupted() = " + thread.isInterrupted());
	}
}

-- 2. 返回值 :

第一次 : thread.interrupted() = true
1
2
第二次 : thread.interrupted() = true
3
4
5
6
7
8
9
10

-- 3. 总结分析 : isInterrupted() 方法 只 判断 被调用对象的 该对象线程的 线程的中断 状态, 不管线程的真实运行状况, 即使当前线程正在运行, 但是线程调用了 interrupt() 方法, 其中断状态为 true, 因此 isInterrupted() 方法的返回值一直是 true;

-- 4. 对比 interrupted() 方法 : interrupted() 方法反应的是真实的线程运行状态, 线程正在运行, 那么返回 false, 如果线程没有运行, 返回 true;

-- 5. 对比 Interrupted() 方法 (静态与普通方法) : isInterrupted 方法是非静态方法, 哪个对象调用返回的就是哪个对象的中断状态; interrupted 是静态方法, 在哪个线程调用就是返回哪个线程的中断状态;

2. 异常法停止线程


(1) 线程循环中正常退出停止

退出方法 : 正常退出线程;

-- 1. 前提 : 线程中执行一个循环;

-- 2. 中断线程 : 执行线程中断操作, 调用 线程的 interrupt() 方法;

-- 3. 查询中断标志 : 在线程中通过调用 interrupted 方法, 查询当前的线程中断标志, 之后该方法就会将中断标志清除;

-- 4. 退出循环 : 如果查询到中断标志后, 直接使用 break 退出循环;

-- 5. 弊端 : 在线程中, 线程没有真正的停止, 线程还是完整的执行了;

线程正常退出代码示例 :

-- 1. 代码 :

public class ExceptionInterruptDeo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			super.run();
			for(int i = 0; i < 500; i ++){
				if(interrupted()){				//判断线程的中断状态, 如果中断直接 break
					System.out.println("停止状态, 退出");
					break;
				}
				System.out.println(i);
			}
			System.out.println("MyThread 线程执行完毕");//线程结束标志
		}
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();		//创建线程并执行
		thread.start();							//启动线程
		Thread.sleep(1);						//沉睡 1 毫秒
		thread.interrupt();						//中断线程
		System.out.println("主线程执行完毕");	//判断主线程停止
	}
}

-- 2. 执行结果 :

... ...
50
51
52
53
54
主线程执行完毕
停止状态, 退出
MyThread 线程执行完毕

-- 3. 总结分析 : 在线程中调用 interrupted() 方法, 查询中断标志(查询后立即清除中断标志), 弊端是停止线程后, 线程还是继续执行后面的逻辑, 继续执行完毕, 自动退出的;

(2) 异常退出线程

异常法退出线程 : 通过抛出一个异常, 来终止线程执行;

-- 1. 前提 : 线程中执行一个循环;

-- 2. 中断线程 : 执行线程中断操作, 调用 线程的 interrupt() 方法;

-- 3. 查询中断标志 : 在线程中通过调用 interrupted 方法, 查询当前的线程中断标志, 之后该方法就会将中断标志清除;

-- 4. 抛出异常退出循环 : 如果查询到中断标志后, 直接抛出一个 InterruptException 异常;

-- 5. 捕获处理异常 : 要将整个 run 方法中的内容使用 try catch 代码块捕获, 因因为异常捕获后还会继续处理 try catch 之后的代码逻辑, 如果 try catch 代码块之后还有代码逻辑, 程序还会执行这段代码;

-- 6. 好处 : 可以自由控制要中断哪些逻辑;

异常捕获规则 :

-- 1. 执行逻辑 : 捕获异常后, 进行异常处理, 然后会继续执行 try catch 代码块 后面的代码逻辑;

-- 2. 异常退出范围可控 : 可以自由控制中断哪些操作, 继续执行哪些操作;

代码测试 :

-- 1. 代码 :

public class ExceptionInterruptDeo {
	public static class MyThread extends Thread {
		@Override
		public void run() {
			try {
				super.run();
				for (int i = 0; i < 500; i++) {
					if (interrupted()) { // 判断线程的中断状态, 如果中断直接 break
						System.out.println("停止状态, 抛出异常退出");
						throw new InterruptedException();
					}// 中断标志 判定结束
					System.out.println(i);
				}//for 循环结束
				System.out.println("MyThread 线程执行完毕");// 线程结束标志
			} catch (InterruptedException e) {
				System.out.println("线程中捕获异常代码块");
				e.printStackTrace();
			} // try catch 代码块
		}//run方法结束
	}//线程结束

	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread(); // 创建线程并执行
		thread.start(); // 启动线程
		Thread.sleep(1); // 沉睡 1 毫秒
		thread.interrupt(); // 中断线程
		System.out.println("主线程执行完毕"); // 判断主线程停止
	}
}

-- 2. 执行结果 :

113
114
115
116
主线程执行完毕
停止状态, 抛出异常退出
线程中捕获异常代码块
java.lang.InterruptedException
	at base.ExceptionInterruptDeo$MyThread.run(ExceptionInterruptDeo.java:12)

-- 3. 总结分析 : 在 run 方法中将整个代码逻辑使用 try catch 代码块包裹, 异常法只能中断 try catch 代码块中的逻辑;

3. sleep() 中停止线程


(1) 先沉睡在终止线程

先 sleep() 再 interrupt() : 先沉睡, 再终止线程, 线程直接就停止了;

代码示例 :

-- 1. 代码 :

public class SleepInterruptDemo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			try {
				System.out.println("线程逻辑开始");
				super.run();
				sleep(1000);	//启动后立即进入沉睡状态, 沉睡 1000ms
				System.out.println("线程逻辑结束");
			} catch (InterruptedException e) {
				System.out.println("捕获到了异常 , 进入了 catch 代码块");
				e.printStackTrace();
			}//catch代码块
			System.out.println("run 方法结束");
		}//run方法
	}//线程

	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();	//新建线程
		thread.start();						//线程启动
		Thread.sleep(100);					//沉睡 100 毫秒, 线程中
		thread.interrupt();					//中断线程
	}
}

-- 2. 执行结果 :

线程逻辑开始
捕获到了异常 , 进入了 catch 代码块
run 方法结束
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at base.SleepInterruptDemo$MyThread.run(SleepInterruptDemo.java:11)

-- 3. 总结分析 : 在沉睡状态下, 如果调用 interrupt() 方法, 线程中会直接抛出 InterruptException 异常;

(2) 先终止线程 再 沉睡

先 终止线程 再 sleep : 先 终止线程, 在 sleep, 那么 sleep 之前的代码需要实现相关逻辑

代码示例 :

-- 1. 代码 : 与上面的区别是 在 sleep 之前有一段 循环逻辑;

public class SleepInterruptDemo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			try {
				System.out.println("线程逻辑开始");
				super.run();
				for(int i = 0; i < 500; i ++)
					System.out.println(i);
				sleep(1000);	//启动后立即进入沉睡状态, 沉睡 1000ms
				System.out.println("线程逻辑结束");
			} catch (InterruptedException e) {
				System.out.println("捕获到了异常 , 进入了 catch 代码块");
				e.printStackTrace();
			}//catch代码块
			System.out.println("run 方法结束");
		}//run方法
	}//线程

	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();	//新建线程
		thread.start();						//线程启动
		thread.interrupt();					//中断线程
		System.out.println("主线程中断线程");
	}
}

-- 2. 执行结果 :

496
497
498
499
捕获到了异常 , 进入了 catch 代码块
run 方法结束
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at base.SleepInterruptDemo$MyThread.run(SleepInterruptDemo.java:12)

-- 3. 总结 : 使用 Interrupt 方法后, 如果正在执行循环, 就不会抛异常退出线程, 进入 sleep 状态后, 会立即抛出异常, 退出线程;

4. stop() 停止线程


(1) stop 方法停止线程的效果

stop 停止线程 :

-- 1. 立即停止 : 调用 stop() 方法停止线程, 比较暴力, 会立即停止当前的线程;

-- 2. 抛出异常 : 使用 stop() 方法停止线程会抛出一个 ThreadDeath 异常, 这个异常可以不捕捉;

-- 3. 适用场景 : 适用该方法停止线程, 前提示 线程的相关数据 和 线程本身 都不再使用了, 否则会造成数据混乱;

stop() 停止线程效果演示 :

-- 1. 代码示例 :

public class StopDemo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			try {
				System.out.println("线程逻辑开始");
				super.run();
				for(int i = 0; i < 5000; i ++){
					System.out.println(i);
					sleep(100);
				}
				System.out.println("线程逻辑结束");
			} catch (InterruptedException e) {
				System.out.println("捕获到了 InterruptedException 异常 , 进入了 catch 代码块");
				e.printStackTrace();
			}//catch代码块
			System.out.println("run 方法结束");
		}//run方法
	}//线程

	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();	//新建线程
		thread.start();						//线程启动
		Thread.sleep(500); 					//沉睡 500ms, 让线程打印 5 个数字
		thread.stop();						//中断线程
		System.out.println("主线程中断线程");
	}
}

-- 2. 运行结果 :

线程逻辑开始
0
1
2
3
4
主线程中断线程

-- 3. 总结分析 : 线程直接中断了, 线程中 run() 方法的最后一行代码也没有执行, 循环逻辑结束也没有执行, 说明线程很暴力的直接退出, 没有任何处理;

(2) stop 方法停止线程 捕获 ThreadDeath 异常

关于异常捕捉 :

-- 1. 捕捉 ThreadDeath 异常 : 线程捕获异常处理后, 还会继续执行 try catch 代码块下面的代码;

-- 2. 不捕捉 ThreadDeath 异常 : 线程直接从 stop 时刻退出, 不会执行下面的代码;

stop() 停止线程 并 捕获异常 效果演示 :

-- 1. 代码示例 : 代码中比上面多了一个 catch ThreadDeath 异常的代码块, 其它一样;

public class StopDemo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			try {
				System.out.println("线程逻辑开始");
				super.run();
				for(int i = 0; i < 5000; i ++){
					System.out.println(i);
					sleep(100);
				}
				System.out.println("线程逻辑结束");
			} catch (InterruptedException e) {
				System.out.println("捕获到了 InterruptedException 异常 , 进入了 catch 代码块");
				e.printStackTrace();
			}catch (ThreadDeath e){
				System.out.println("捕获到了 ThreadDeath 异常 , 进入了 catch 代码块");
				e.printStackTrace();
			}//catch代码块
			System.out.println("run 方法结束");
		}//run方法
	}//线程

	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();	//新建线程
		thread.start();						//线程启动
		Thread.sleep(500); 					//沉睡 500ms, 让线程打印 5 个数字
		thread.stop();						//中断线程
		System.out.println("主线程中断线程");
	}
}

-- 2. 运行结果 :

线程逻辑开始
0
1
2
3
4
主线程中断线程
捕获到了 ThreadDeath 异常 , 进入了 catch 代码块
run 方法结束
java.lang.ThreadDeath
	at java.lang.Thread.stop(Unknown Source)
	at com.hanshuliang.thread.StopDemo.main(StopDemo.java:31)

-- 3. 总结分析 : 如果捕获了 ThreadDeath 异常, 就会处理这个异常, 并会执行异常处理后面的代码, run() 方法的最后一行代码也执行完毕了;

5. return 停止线程

return 停止线程说明 :

-- 1. 执行过程 : 线程运行中, 随时监测中断标记, 如果检测到中断标记后, 直接 return 退出 run 方法;

-- 2. 不建议使用该方法, 多个 return 会污染代码;

return 退出演示 :

-- 1. 代码示例 :

public class ReturnDemo {
	public static class MyThread extends Thread{
		@Override
		public void run() {
			super.run();
			for(int i = 0; i < 500; i ++){
				if(interrupted()){				//判断线程的中断状态, 如果中断直接 break
					System.out.println("停止状态, return 退出");
					return;
				}
				System.out.println(i);
			}
			System.out.println("MyThread 线程执行完毕");//线程结束标志
		}
	}
	public static void main(String[] args) throws InterruptedException {
		MyThread thread = new MyThread();		//创建线程并执行
		thread.start();							//启动线程
		Thread.sleep(1);						//沉睡 1 毫秒
		thread.interrupt();						//中断线程
		System.out.println("主线程执行完毕");	//判断主线程停止
	}
}

-- 2. 执行结果 :

... ...
35
36
37
38
39
主线程执行完毕
停止状态, return 退出

-- 3. 总结分析 : 使用 return 直接退出 run 方法, 确实实现了立即停止线程的目的, 但是我们还是建议使用 异常法 控制线程停止;

转载注明出处 : http://blog.csdn.net/shulianghan/article/details/52369486

时间: 2024-07-30 17:44:54

【Java 语言】Java 多线程 一 ( 线程启动 | 线程中断 )的相关文章

Java语言基础-多线程-①线程的创建和启动

简单阐释进程和线程 对于进程最直观的感受应该就是“windows任务管理器”中的进程管理: (计算机原理课上的记忆已经快要模糊了,简单理解一下):一个进程就是一个“执行中的程序”,是程序在计算机上的一次运行活动.程序要运行,系统就在内存中为该程序分配一块独立的内存空间,载入程序代码和资源进行执行.程序运行期间该内存空间不能被其他进程直接访问.系统以进程为基本单位进行系统资源的调度和分配.何为线程?线程是进程内一次具体的执行任务.程序的执行具体是通过线程来完成的,所以一个进程中至少有一个线程.回忆

设计模式——单例模式(Java)——考虑多线程环境下的线程安全问题

设计模式--单例模式(Java)--考虑多线程环境下的线程安全问题 一:单例模式概念 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例 二:单例模式的实现方式 特别注意,在多线程环境下,需要对获取对象实例的方法加对象锁(synchronized) 方式一:(懒汉式)程序执行过程中需要这个类的对象,再实例化这个类的对象 步骤: 1.定义静态私有对象 2.构造方法私有化保证在类的外部无法实例化该类的对象 3.定义对外开放的静

基于JAVA语言的多线程技术

1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资源的基本单位:线程是操作系统进行调度,时间分配的基本单位: 进程由内核对象和地址空间两部分构成,内核对象就是一小块记录进程信息的内存,只允许操作系统访问:地址空间就是存放数据和程序的空间: 2.多线程运行机制 对于单个CPU,在每个时间点只能只能执行一个线程,多线程的实现是基于对时间片的轮回机制的,

Java语言是多线程的

在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建. 通常有两种方法来创建线程: 其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程, 其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程.值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码. 线程的活动由一组方法来控制.Java语言支持多个线程的同

Java线程模型、线程状态 - 线程(1)

1. 概述 众所周知,线程 - Thread 是比进程 - Progress 更轻量级的调度单位.简单来说,引入线程带来的好处是: 可以把一个进程 的资源分配和执行调度分开,各个线程 既可以共享进程 资源(内存地址.文件I/O等),又可以独立调度. 线程实现方式: 主流的操作系统都实现了线程 ,而编程语言一般会提供关于线程 的统一API操作.那么,编程语言如何去调用系统线程 呢?这方面主要有3种方式: 使用内核线程 - Kernel Thread. 一对一线程模型 ,这个最重要,下面详细讲. 使

java语言的特性及应用

java语言定义: Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言. Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动电话和互联网,同时拥有全球最大的开发者专业社群. 组成: Java由四方面组成:●Java编程语言,即语法.●Java文件格式,即各种文件夹.文件的后缀.●Java虚拟机(JVM),即处理*.class文件的解释器.●Java应用程序接口(Java API). Java分为三个体系,分别为Java

Java语言的基础知识9

第十一章(线程) 1.通过String name=Thread.currentThread().getName();来获取当前线程的名称. 2.多次启动一个线程或者启动一个已经运行的线程是非法的,会抛出IllegalThreadStateException异常对象. Thread.sleep((int)Math.random()*10000); 3.java提供了Runnable接口使继承了其他类之后同样可以实现该接口达到创建线程的目的Runabble接口同样定义了Run方法. 实现Runnab

java语言程序

第一章 Jave语言基础 1.1 Java语言的特点 领会Java语言的特点.关键字 1010-11.Java语言采用多种机制来保证可移植性,其中最主要的是______.虚拟机 1110-11.Java语言是一种 ____强类型语言___ 语言,它约束程序员必须遵守规定编写程序,能让编译器检测出程序中尽可能多的错误. 1.2 Java应用程序和小应用程序 识记      Java应用程序与小应用程序的特点和区别 11.一个应用程序必须在某个类中定义的方法是______.main() 1201-

java语言具备的11大特点

中软国际武汉java培训专家介绍java语言具备的11大特点. 1.Java语言是简单的 Java 语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java.另一方面,Java丢弃了C++中很少使用的.很难理解的.令人迷惑 的那些特性,如操作符重载.多继承.自动的强制类型转换.特别地,Java语言不使用指针,并提供了自动的废料收集,使得程序员不必为内存管理而担忧. 2.Java语言是一个面向对象的 Java 语言提供类.接口和继承等原语,为了简单起见,只支持类之间的单继承,