/   今日科技快讯   /

近日发布的《2021年企业年终奖发放计划调研报告》显示,2021年年终奖的人均水平为2.3万元, 2021年企业年终奖额度相当于员工2.1倍月薪。41%的企业表示2021年年终奖额度有所提升,31%的企业年终奖额度和2020年持平,企业年终奖提升额度大多在10%以内。从行业来看,金融行业2021年终奖平均水平为4.52万元,领跑各行业;高科技行业相比去年上涨11%,涨幅高居各行业之首。

/   作者简介   /

本篇文章来自android超级兵的投稿,文章主要分享了他所整理的线程相关的知识,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

android超级兵的博客地址:

https://blog.csdn.net/weixin_44819566

/   正文   /

常见创建线程的几种方式

方式一

方式二

方式三

方式一,方式二和方式三的启动代码:

public static void main(String[] args) throws ExecutionException, InterruptedException {// 方式一MyThread myThread = new MyThread();myThread.start();// 方式二MyRunnable myRunnable = new MyRunnable();new Thread(myRunnable).start();// 方式三MyCallable myCallable = new MyCallable();FutureTask<String> futureTask = new FutureTask<String>(myCallable) {@Overrideprotected void done() {System.out.println("方式三开始前!");super.done();System.out.println("方式三执行后!");try {System.out.println("done内部获取方式三返回结果:" + get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}};// 方式三启动线程new Thread(futureTask).start();System.out.println("获取方式三返回结果:" + futureTask.get());
}

运行结果:

三种方式的区别:

  • extend Thread 需要手动重写run方法

  • implements Runnable 需要将当前runnable对象传入Thread中

  • implements Callable<*> 可以获取到thread的返回值,并且不能直接传给thread启动,需要采用FutureTask来配合,并且可以通过FutureTask.get()获取到实现 implements Callable的<*>的call的返回值

Thread.start() 和 Thread.run() 的区别

再来看一段代码。

start

Client4Thread client4Thread = new Client4Thread();
client4Thread.start();

运行结果:

thread:Thread-0

run

Client4Thread client4Thread = new Client4Thread();
client4Thread.run();

运行结果:

thread:main

结论

如果调用Thread.run()方法相当于一个普通类调用了一个run方法,并没有开启子线程。相当于这样:

public static class User {public void run() {System.out.println("User.run" + Thread.currentThread().getName());}}

client4Thread.run()等价于User.run()!

Client4Thread client4Thread = new Client4Thread();
//        client4Thread.start();// 效果一样
client4Thread.run();
//
//
new User().run();

Thread.join() 线程串形化

先来看使用场景:

现在有三个线程,同时运行,先来运行看看结果:

可以看出,每次执行顺序都不同…如果你想让他同步执行,你可以这样做。

结论

join的作用就是将线程串行化,需要注意的是,join()一定要放在现场开启(start())后。

Thread.Interrupt()线程中断

运行代码:

运行结果为:

可以看出,虽然向子线程发送了中断信号,但是线程并不会执行终端,而是一直存活着。如果想要线程中断,只需要在Thread中判断一下isInterrupted()即可。例如这样:

运行结果为:

小坑

如果你需要在!isInterrupted()中休眠一下,例如这样:

这样是不可以的,因为Thread.sleep会捕获中断信号,并且将中断信号改为false。最终导致结果成这样了。

最终就会导致捕获到了中断异常,但是Thread.sleep()擅自更改了...只需要在捕获到InterruptedException异常的时候,再次更改状态即可。例如这样:

当然不仅是extend Thread这种写法可以中断线程,implements Runnable当前也可以中断线程,比如这样写:

效果是一样的,就不重复展示了…

Thread 数据共享 synchronized(隐式锁)

还是先来看简单的案例。现在有2个线程,需要同时对count ++,例如这样:

结果为:

可以看出,每次运行的结果都不一样?这是为什么?因为这里是循环添加1000 * 100次,在2个线程同时跑的时候,就会出现两个count同时执行的情况,所以导致数字总是不太对。这里只需要让他同步起来(添加同步锁)即可,例如这样:

常见锁的写法

锁某一个类的class。

private static final Object object = new Object();public static void addCount() {for (int i = 0; i < countLength; i++) {synchronized (object) {count++;}}
}

锁当前对象的this。

public synchronized void addCount2() {.....
}

锁指定对象的class。

public static void addCount() {for (int i = 0; i < countLength; i++) {synchronized (Client2.class) {count++;}}}

Thread线程隔离(ThreadLocal)

什么是线程隔离,还是先看代码:

还是先来看结果:

可以看出,每一次的运行效果都是不一样的这是因为启动(start)的时候,线程只是就绪状态,只是通知JVM我可以执行了,真正的执行是JVM来调用的。以最后一次结果来看问题:

ThreadName:Thread-1    threadIndex:1   count:2
ThreadName:Thread-4    threadIndex:4   count:11
ThreadName:Thread-3    threadIndex:3   count:7
ThreadName:Thread-2    threadIndex:2   count:4
ThreadName:Thread-0    threadIndex:0   count:2

先来分析一下代码:main方法中,开启了5个线程,并且将下标传了进去,然后再MyThreadLocal具体对下表累加。

需求分析

既然说到是线程隔离,那么想要的效果应该是假如现在传入进来的是5,那么通过。

count+=threadIndex;

应该结果是6,而不应该吧其他线程的结果也算到当前线程头上这段话说的比较绕,直接来看ThreadLocal就明白了!

启动的时候添加了一个Thread.join()使线程顺序执行…

直接看效果:

可以看出,现在就实现了线程的隔离。如果你阅读过Handler源码,也会发现他内部使用了ThreadLocal来进行线程隔离。不过这里线程隔离隔离的是Lopper,为了保证一个线程只有一个looper。瞟一眼handler的代码:

显示锁

可重入锁 (ReentrantLock)

什么是可重入?

int count = 0;
public synchronized void test() {count++;if (count <= 10) {test();}}

先拿synchronized来举例,以当前的认知来看,如果递归情况下,synchronized一定会被锁死,因为第一次执行test()的时候,还没有释放锁就进行了第二次的加锁。但是从结果来看,毫无问题,因为synchronized是具有可重入性的,可重入就是指如果同一个实例的话,可重新进入。ReentrantLock也是同样的道理,来看看ReentrantLock的使用:

结果还是那个结果:

这里需要注意的是,在使用隐式锁的时候,一定要放在try { ... } finally { .. }代码块中。这样做是因为即使抛出异常,也会吧锁释放掉,不会出现死锁情况。规范示例:

lock.lock();
try{count++;
} finally {lock.unlock();
}

读写锁 (ReentrantReadWriteLock)

要想突出ReentrantReadWriteLock的效果,那就必须有对比,这里就和synchronized来比较!

思路

开启3个写线程,30个读线程,来模拟实际开发中的读取操作。通过同步锁(synchronized)和读写锁的实际效果来看他们的运行机制!再来看代码思路。

StudentImpl

getThread

setThread

运行

可以看出,效果是十分的明显,从变化中也可以看出,如果要进行大量的读写操作,使用读写锁效率会大大的提高!

课外知识 volatile!

volatile本不属于Thread的知识,但是既然说到这么多关键字,那就提一嘴吧!还是一段代码引出区别。

未加volatile关键字

效果图:

可以看出,不加volatile关键字isRun,即使是改变了,线程中也是没反应,接受不到…再来看看添加volatile关键字:

效果图:

结果显而易见,一旦标记了volatile isRun变量,只要发生改变就回直接通知JVM来改变当前的状态!!

完整代码地址:

https://gitee.com/lanyangyangzzz/thread-project

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

在微软工作365天,还你一个我眼中更加真实的微软

Jetpack全家桶中最受欢迎的一定是它

欢迎关注我的公众号

学习技术或投稿

长按上图,识别图中二维码即可关注

Java线程知识你还记得多少?相关推荐

  1. Java线程知识整理汇总

    优先级 priority 所有线程都有优先级属性 priority,值比较大的会被优先执行 priority 最小值是 1,最大值是 10,默认值是 5 子线程 priority 的初始值跟父线程的 ...

  2. java线程知识体系

    1 java多线程基础概念 2 java线程生命周期 3 线程三种创建方式与线程池的应用 4 多线程的安全问题的解决与死锁 5 java synchronized静态同步方法与非静态同步方法,同步语句 ...

  3. Java 线程 知识

    学习线程 先了解 线程与进程之间的关系 线程:  (线程是cpu调度的最小单位) 我们可以说是进程中执行运算的最小单位. 进程: (进程是资源分配的最小单位) 我们可以说是一段程序执行的过程, 如果还 ...

  4. java线程知识梳理_Java多线程——多线程相关知识的逻辑关系梳理

    1 学习多线程知识的根本目标 多线程知识的根本目标是:设计稳健的并发程序. 当然,本文无法回答这个实践性很强的问题(这与具体的业务相关,涉及到具体的策略),本文主要阐述相关知识之间的关系,希望初学者不 ...

  5. java线程知识总结

    (1)线程的状态以及互相转换 NEW,RUNNABLE,WAITING,TIMED_WAITING,BLOCKED,TERMINATED new  Thread()  ----NEW 准备就绪,等到c ...

  6. 假期余额不足,这些并发知识你还记得吗?

    假期最后一天了!假期最后一天了!假期最后一天了! 这是一个人看看到就心慌的现实消息,壮丽 70 年,奋斗新时代,与祖国同庆之后,我们需要回归正轨了(这句话貌似无比的刺耳),祖国会有无数个 70 年,我 ...

  7. 写了这么久Java项目,是否还记得你的第一行Java代码

    前言 个人情况 首先介绍一下本人的情况,我来自于一个双非渣渣二本学院,目前处于大四阶段,由于在小学的时候就开始接触了电脑,一直以来也对IT的各方面有着浓厚的兴趣,所以在高考结束填写志愿书的时候,就毅然 ...

  8. java线程知识初级

    线程 1.基本概念 多线程是实现并发机制的一种有效手段.进程和线程一样,都是实现并发的一个基本单位.线程是比进程更小的执行单位,线程是进程的基础之上进行进一步的划分.所谓多线程是指一个进程在执行过程中 ...

  9. 技术理论-【Thread】- java线程知识总结

    概念: 背景 程序,进程,线程,多任务,主线程 三高应用(高可用,高性能,高并发) 学习理论(守破离,断舍离), lambda(JDK8,内部类<静态,局部,匿名,lambda>,函数式编 ...

最新文章

  1. 【云栖大会】人工智能:智,在云端
  2. python执行命令并返回结果集_Python接口测试结果集实现封装比较
  3. 笔记-信息系统安全管理-信息安全(混合)
  4. 国产浏览器 linux,360安全浏览器推出国产操作系统版,在deepin上架获得高度点赞...
  5. Catalan数的理解
  6. java获取IP地址:
  7. JMeter察看结果树的显示模式详解
  8. Ubuntu 配置Tomcat环境(转载)
  9. iview2.0 bug之+8 区的 DatePicker
  10. 5种方式实现 Java 单例模式
  11. Java解决高并发下商品库存更新
  12. SpringBoot 配置文件存放位置及读取顺序
  13. 电脑计算机硬盘内存满了怎么清理,电脑磁盘空间怎么清理 电脑磁盘空间清理方法【详解】...
  14. 低配置享受3D立体游戏 手把手教你设置
  15. PYsystem003 中职网络安全
  16. 3D打印Arduino 四轴飞行器
  17. HC32l130单片机的delay函数怎么写
  18. numpy选择特定的行列
  19. 计算机检查磁盘,教你win7系统电脑检测到磁盘错误的解决教程
  20. 腾讯:互联网金融行业HBase实践与创新

热门文章

  1. 熊猫终于过去了....
  2. [Unity]腾讯SDK踩坑之路(4)--GCloud+GVoice坑
  3. 基于JAVA人脸识别公司签到系统(Springboot框架+AI人工智能) 开题报告
  4. 论文阅读_胶囊网络CapsNet
  5. 公路领域新型基础设施建设报告(附下载)
  6. java中操作字符串都有哪些类,他们之间有什么区别?
  7. 基于入侵杂草算法的函数寻优算法
  8. esp8266显示农历
  9. 剑指offer 李乐约起01
  10. 同余问题(含证明)整理(篇目①:定义、性质与两个简单定理)