昨天已经写了:html
若是没看的同窗建议先去阅读一遍哦~java
在写文章以前通读了一遍《Java 核心技术 卷一》的并发章节和《Java并发编程实战》前面的部分,回顾了一下之前写过的笔记。从今天开始进入多线程的知识点咯~数据库
我其实也是至关于从零开始学多线程的,若是文章有错的地方还请你们多多包含,不吝在评论区下指正呢~~编程
声明本文使用的是JDK1.8
实现多线程从本质上都是由Thread类来进行操做的~咱们来看看Thread类一些重要的知识点。Thread这个类很大,不可能整个把它看下来,只能看一些常见的、重要的方法。c#
顶部注释的咱们已经解析过了,若是不知道的同窗可前往:多线程三分钟就能够入个门了!安全
咱们在使用多线程的时候,想要查看线程名是很简单的,调用Thread.currentThread().getName()
便可。微信
若是没有作什么的设置,咱们会发现线程的名字是这样子的:主线程叫作main,其余线程是Thread-x多线程
下面我就带着你们来看看它是怎么命名的:并发
nextThreadNum()
的方法实现是这样的:ide
基于这么一个变量-->线程初始化的数量
点进去看到init方法就能够肯定了:
看到这里,若是咱们想要为线程起个名字,那也是很简单的。Thread给咱们提供了构造方法!
下面咱们来测试一下:
public class MyThread implements Runnable { @Override public void run() { // 打印出当前线程的名字 System.out.println(Thread.currentThread().getName()); } }
测试:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //带参构造方法给线程起名字 Thread thread1 = new Thread(myThread, "关注公众号Java3y"); Thread thread2 = new Thread(myThread, "qq群:742919422"); thread1.start(); thread2.start(); // 打印当前线程的名字 System.out.println(Thread.currentThread().getName()); } }
结果:
固然了,咱们还能够经过setName(String name)
的方法来改掉线程的名字的。咱们来看看方法实现;
检查是否有权限修改:
至于threadStatus这个状态属性,貌似没发现他会在哪里修改:
守护线程是为其余线程服务的
守护线程有一个特色:
使用线程的时候要注意的地方
setDaemon(boolean on)
测试一波:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //带参构造方法给线程起名字 Thread thread1 = new Thread(myThread, "关注公众号Java3y"); Thread thread2 = new Thread(myThread, "qq群:742919422"); // 设置为守护线程 thread2.setDaemon(true); thread1.start(); thread2.start(); System.out.println(Thread.currentThread().getName()); } }
上面的代码运行屡次能够出现(电脑性能足够好的同窗可能测试不出来):线程1和主线程执行完了,咱们的守护线程就不执行了~
原理:这也就为何咱们要在启动以前设置守护线程了。
线程优先级高仅仅表示线程获取的CPU时间片的概率高,但这不是一个肯定的因素!
线程的优先级是高度依赖于操做系统的,Windows和Linux就有所区别(Linux下优先级可能就被忽略了)~
能够看到的是,Java提供的优先级默认是5,最低是1,最高是10:
实现:
setPriority0
是一个本地(navite)的方法:
private native void setPriority0(int newPriority);
在上一篇介绍的时候其实也提过了线程的线程有3个基本状态:执行、就绪、阻塞
在Java中咱们就有了这个图,Thread上不少的方法都是用来切换线程的状态的,这一部分是重点!
其实上面这个图是不够完整的,省略掉了一些东西。后面在讲解的线程状态的时候我会从新画一个~
下面就来说解与线程生命周期相关的方法~
调用sleep方法会进入计时等待状态,等时间到了,进入的是就绪状态而并不是是运行状态!
因而乎,咱们的图就能够补充成这样:
调用yield方法会先让别的线程执行,可是不确保真正让出
因而乎,咱们的图就能够补充成这样:
调用join方法,会等待该线程执行完毕后才执行别的线程~
咱们进去看看具体的实现:
wait方法是在Object上定义的,它是native本地方法,因此就看不了了:
wait方法实际上它也是计时等待(若是带时间参数)的一种!,因而咱们能够补充咱们的图:
线程中断在以前的版本有stop方法,可是被设置过期了。如今已经没有强制线程终止的方法了!
因为stop方法可让一个线程A终止掉另外一个线程B
总而言之,Stop方法太暴力了,不安全,因此被设置过期了。
咱们通常使用的是interrupt来请求终止线程~
Thread t1 = new Thread( new Runnable(){ public void run(){ // 若未发生中断,就正常执行任务 while(!Thread.currentThread.isInterrupted()){ // 正常任务代码…… } // 中断的处理代码…… doSomething(); } } ).start();
再次说明:调用interrupt()并非要真正终止掉当前线程,仅仅是设置了一个中断标志。这个中断标志能够给咱们用来判断何时该干什么活!何时中断由咱们本身来决定,这样就能够安全地终止线程了!
咱们来看看源码是怎么讲的吧:
再来看看刚才说抛出的异常是什么东东吧:
因此说:interrupt方法压根是不会对线程的状态形成影响的,它仅仅设置一个标志位罢了
interrupt线程中断还有另外两个方法(检查该线程是否被中断):
上面还提到了,若是阻塞线程调用了interrupt()方法,那么会抛出异常,设置标志位为false,同时该线程会退出阻塞的。咱们来测试一波:
public class Main { /** * @param args */ public static void main(String[] args) { Main main = new Main(); // 建立线程并启动 Thread t = new Thread(main.runnable); System.out.println("This is main "); t.start(); try { // 在 main线程睡个3秒钟 Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("In main"); e.printStackTrace(); } // 设置中断 t.interrupt(); } Runnable runnable = () -> { int i = 0; try { while (i < 1000) { // 睡个半秒钟咱们再执行 Thread.sleep(500); System.out.println(i++); } } catch (InterruptedException e) { // 判断该阻塞线程是否还在 System.out.println(Thread.currentThread().isAlive()); // 判断该线程的中断标志位状态 System.out.println(Thread.currentThread().isInterrupted()); System.out.println("In Runnable"); e.printStackTrace(); } }; }
结果:
接下来咱们分析它的执行流程是怎么样的:
2018年4月18日20:32:15(哇,这个方法真的消耗了我很是长的时间).....感谢@开始de痕迹的指教~
该参考资料:
能够发现咱们的图是尚未补全的~后续的文章讲到同步的时候会继续使用上面的图的。在Thread中重要的仍是那几个能够切换线程状态的方法,还有理解中断的真正含义。
使用线程会致使咱们数据不安全,甚至程序没法运行的状况的,这些问题都会再后面讲解到的~
以前在学习操做系统的时候根据《计算机操做系统-汤小丹》这本书也作了一点点笔记,都是比较浅显的知识点。或许对你们有帮助
参考资料:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够 关注微信公众号:Java3y。为了你们方便,刚新建了一下 qq群:742919422,你们也能够去交流交流。谢谢支持了!但愿能多介绍给其余有须要的朋友
文章的目录导航: