文章目录
- 一、Thread类的属性和方法
- 二、Thread类中方法的应用
- (1)利用join()实现并发排序
- (2)yield()的应用
- (3)线程中断 interrupt
提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、Thread类的属性和方法
二、Thread类中方法的应用
(1)利用join()实现并发排序
四个线程分别对各自的每一段进行排序
(Arrays.sort)
当四个线程的工作全部完成之后,即
{ t1.join(); t2.join(); t3.join(); t4.join() }
执行4路归并…(省略)
前提: 一个进程下的线程,共享的是同一块内存资源
import java.util.Arrays;
/**
* 多线程并发排序
*/
public class ConcurrentSort {
// 进行排序的线程
static class SortWorker extends Thread {
private final long[] array;
private final int fromIndex;
private final int toIndex;
// 利用构造方法,将待排序的数组区间情况,传入
// 对 array 的 [fromIndex, toIndex) 进行排序
SortWorker(long[] array, int fromIndex, int toIndex) {
this.array = array;
this.fromIndex = fromIndex;
this.toIndex = toIndex;
}
@Override
public void run() {
// 具体的排序过程,这里使用 Array.sort 做模拟
Arrays.sort(array, fromIndex, toIndex);
}
}
// 记录排序耗时
public static void main(String[] args) throws InterruptedException {
long[] array = ArrayHelper.generateArray(4000_0000);
// 分别是
// [0, 1000_0000)
// [1000_0000, 2000_0000)
// [2000_0000, 3000_0000)
// [3000_0000, 4000_0000)
long s = System.currentTimeMillis();
Thread t1 = new SortWorker(array, 0, 1000_0000);
t1.start(); // 先让 t1 进入就绪队列
Thread t2 = new SortWorker(array, 1000_0000, 2000_0000);
t2.start(); // 再让 t2 进入就绪队列
Thread t3 = new SortWorker(array, 2000_0000, 3000_0000);
t3.start(); // 然后让 t3 进入就绪队列
Thread t4 = new SortWorker(array, 3000_0000, 4000_0000);
t4.start(); // 最后让 t4 进入就绪队列
// 把 4 个线程放入就绪队列的顺序是有序的
// 但,哪个线程会被调度器选中,我们就不知道了,可以认为是随机的
// 4 个线程开始分别的进行排序了
// 等待 4 个线程全部排序完毕,这 4 个 join 没有前后顺序
t1.join();
t2.join();
t3.join();
t4.join();
// 4 个线程一定全部结束了
// TODO:进行 4 路归并,将 4 个有序数组,归并成一个有序数组
long e = System.currentTimeMillis();
// 计算耗时
long elapsed = e - s;
System.out.println(elapsed);
}
}
回到目录…
(2)yield()的应用
yield()主要用于执行一些耗时较久的计算任务时,为让防止计算机处于“卡顿”的现象,时不时的让出一些CPU资源,给OS内的其他进程。
让出CPU,会引导OS进行新的一轮线程调度。(上下文切换=保存当前线程的PC)
以后,等我们被分配CPU时,恢复我们之前保存的PC
现象:我们线程的代码是接着上一次的继续执行。
线程是OS调度的单位。
线程是OS分配CPU资源的单位。
我们程序员的角度来讲:线程是抢夺CPU的工具。
public class Main {
static class PrintWhoAmI extends Thread {
private final String who;
public PrintWhoAmI(String who) {
this.who = who;
}
@Override
public void run() {
while (true) {
System.out.println("我是 " + who);
if (who.equals("张三")) {
// 线程并没有结束和暂停,而是尽可能的让出CPU
Thread.yield();
}
}
}
}
public static void main(String[] args) {
PrintWhoAmI 张三 = new PrintWhoAmI("张三");
PrintWhoAmI 李四 = new PrintWhoAmI("李四");
张三.start();
李四.start();
}
}
回到目录…
(3)线程中断 interrupt
事件:
A叫来B干活。
一些突发情况发生了,需要让B停止工作(即使分配它的任务还没有完成)
所以A需要让B停止。
中断的方法:
①暴力停止,直接将B给kill掉。不知道B的工作进行到哪一步(不可控)。
void stop(); // 已经被废弃
②优雅的协商,A给B发送终止的信号,B收到信号后主动停止。
void interrupt();
接收停止信号时,B的状态:
情况1: B正在正常执行代码,可以通过一个方法来判定
静态方法 Thread.interrupted(); // 检测当前线程是否被中止
true:有人让我们停止。
false: 没人让我们停止
B的代码类似: .
while (true) {
//写代码
//看一眼手机,有没有人让我们停止
if (Thread.interrupted()) {
//有人让我们停止,停止
break; //也可以其他方式
}
}
至于B要不要停,完全是代码控制的
情况2: B可能正处于休眠状态(比如sleep、join) ,意味着B无法立即执行
此刻,JVM的处理方式是,以异常形式通知B : InterruptedException
当B处于休眠状态时,捕获了InterruptedException异常,代表有人让我们停止。
具体要不要停,什么时候停,怎么停,完全自己做主
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
/**
* 中断线程的方法, interrupt()的应用
*/
public class Main_Interrupt {
static class B extends Thread {
@Override
public void run() {
while (true) {
for (int i = 0; i < 1000; i++) {
System.out.println("我正在写代码");
}
// 休息之前,检查有没有人让我们停止
if (Thread.interrupted()) {
// 有人让我们停止
break; // 跳出 while 循环
}
// 每写 1000 行,休息 1s
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// 休息期间,有人让我们停止
break; // 跳出 while 循环 // 大概率是这里
}
// 休息之后,检查有没有人让我们停止
if (Thread.interrupted()) {
// 有人让我们停止
break; // 跳出 while 循环
}
}
System.out.println("B 停下来了");
}
}
public static void main(String[] args) {
B b = new B();
b.start();
// 让 B 停止工作
Scanner scanner = new Scanner(System.in);
System.out.println("输入任意字符,停止 B 的工作");
scanner.nextLine(); // 主线程阻塞在这里,直到用户输入内容
b.interrupt(); // 让 b 停止
}
}
回到目录…
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java多线程的学习,认识了Thread类中常见的属性和方法,还有部分方法的应用。之后的学习内容将持续更新!!!