目录
6.1id 本进程(JVM进程)内存分配的唯一id,只能get不能set
6.3在Java代码中看到的线程状态(只能获取不能设置(不能set),状态的变更是JVM控制的)
6.5前台线程vs后台线程/精灵线程(deason)/守护线程
7.JDK中自带观察线程的工具 (jconsole.eve)
9.2.2和另一个线程协商 void interrupt()
进程是操作系统资源分配的单位
线程是操作系统进行调度的单位
程序执行一次的过程表现为一个进程,main所在的线程是主线程,主线程中可以运行对应操作来创建运行其他线程。
1.操作系统级别的线程的特点(只针对os级别)
操作系统针对同一个进程下的线程实现连坐机制:
一旦一个进程异常退出,操作系统会自动关闭所在的整个进程。
2.Java线程
2.1Java线程在代码中的体现
Java.lang.Thread类(包括其子类)的一个对象
2.2在代码中创建线程
a.通过继承Tread类,并重写run方法。(常用)
实例化该类对象=>Tread对象
b.通过实现Runnable接口,并重写run方法
实例化Runnable对象
利用Runnable对象构建一个Tread对象
3.启动线程
当手中有一个Tread对象时,调用其start()方法即可启动。
注意:一个已经调用过start(),就不能再调用start()了,再调用就会有异常发生。
千万不要调用成run()
3.主线程与子线程执行的顺序(具有随机性)
一般情况下依旧是主线程先执行,那么什么时候子线程语句会先执行呢?
4.线程和方法调用栈的关系:每个线程都有自己独立的调用栈
总结:调用同一个方法,指令相同,但是方法调用栈不同,处理的数据也不同,互相执行自己的,独立,互不影响。
5.栈和栈帧
6.线程中常见的属性
6.1id 本进程(JVM进程)内存分配的唯一id,只能get不能set
![]()
6.2name(名字) 方便给开发者看
默认情况下是Thread-0、Tread-1,这样,可以get也可以set。
可以通过setName(....)设置,也可以通过Tread(...)构造方法设置
6.3在Java代码中看到的线程状态(只能获取不能设置(不能set),状态的变更是JVM控制的)
![]()
6.4可以设置自己的优先级(get/set)
但是这个优先级只是给JVM一些建议,不能强制让哪个线程先被调度。
6.5前台线程vs后台线程/精灵线程(deason)/守护线程
前台线程:一般是做一些支持的工作。
后台线程:做一些有交互的工作。
不加时候的打印
问:JVM进程什么时候才能退出?
1.必须要求所有的前台进程都退出。
2.和主线程无关,主线程的退出并不影响程序的结束。
和后台线程无关,后台线程正在工作,也正常退出。
6.6常见属性的总结
id(get)、name(set/get)、状态(get)、优先级(set/get)
7.JDK中自带观察线程的工具 (jconsole.eve)
8.Tread几个常见的静态方法
8.1Tread.sleep();让线程休眠,让那个当前线程从运行=>阻塞。
TimeUnit*.sleep();
8.2Tread.currentTread();返回当前线程的引用
8.2Tread.yield();让出CPU,运行=>就绪,随时可以被调度会CPU。
![]()
9.线程的控制:
9.1控制另外线程的方法join()
多线程代码:
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(4_000_0000); // 分别是 // [0, 1000_0000) // [1000_0001, 2000_0000) // [2000_0001, 4000_0000) // [3000_0001, 4000_0000) long s = System.currentTimeMillis(); Thread t1 = new SortWorker(array, 0, 1000_0000); t1.start(); Thread t2 = new SortWorker(array, 1000_0001, 2000_0000); t2.start(); Thread t3 = new SortWorker(array, 2000_0001, 3000_0000); t3.start(); Thread t4 = new SortWorker(array, 3000_0001, 4000_0000); t4.start(); // 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); } }
单线程代码:
做了数组的归并排序(四个线程分别对各自的每一段进行排序Arrays.sort(),当t1、t2、t3、t4工作全部完成之后,执行四路归并,前提是一个进程下的线程,共享同一块内存)
而与单线程做对比,就会快很多
9.2通知线程停止
9.2.1暴力停止 void stop()
一般不用这个,已经deprecate了
不可控,把B杀掉,不知道B把工作进行如何了
9.2.2和另一个线程协商 void interrupt()
只是发了一个消息,给B设置了一个停止标志,实际上并不会影响B的运行。
10.使用多线程的场景
10.1:用多线程来提高效率。
10.2:当另一个执行流因故阻塞时,我们需要新的执行流。