定时调度

1000ms后执行 每隔500ms执行一次

package cn.hanquan.test;import java.util.Timer;
import java.util.TimerTask;/** 定时执行*/
public class MyTimer {public static void main(String[] args) {Timer t = new Timer();t.schedule(new MyTask(), 1000, 500);// 1000ms后执行 每隔500ms执行一次}
}class MyTask extends TimerTask {@Overridepublic void run() {System.out.println("大脑放松一下,打印一个hello");}
}

进阶:使用Quartz

官方文档给了很多examples,想实现什么功能,可以直接复制examples里的代码,加以修改。


指令重排

指令重排对多线程是有影响的



sxt Java 300级说这个代码会发生指令重排,但是我测试没有发生重排…

package cn.hanquan.test;import java.util.Timer;
import java.util.TimerTask;/** 指令重排*/
public class HappenBefore {public static int a = 0;public static boolean flag = false;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 5000; i++) {Thread t1 = new Thread(() -> {a = 1;flag = true;});Thread t2 = new Thread(() -> {if (flag) {a *= 1;// a不变}if (a == 0) {System.out.println("a=" + a);}});t1.start();t2.start();t1.join();t2.join();}}
}

volatile

  • volatile用来保证数据的同步,也就是可见性

使用volatile可以让工作内存实时保证最新,保证了同步的数据可见。有一种说法:volatile是轻量级的synchronized,比synchronized占用的资源少,同时也可以避免指令重排

未使用 Volatile

运行之后一直不结束,cpu没有时间同步内存中的值

package cn.hanquan.test;/** 指令重排*/
public class VolatileTest {public static int num = 0;public static void main(String[] args) throws InterruptedException {new Thread(() -> {while (num == 0) {}}).start();Thread.sleep(500);num = 1;}
}


使用 Volatile

程序可以正常结束

package cn.hanquan.test;/** 指令重排*/
public class VolatileTest {public volatile static int num = 0;public static void main(String[] args) throws InterruptedException {new Thread(() -> {while (num == 0) {}}).start();Thread.sleep(500);num = 1;}
}


ThreadLocal

ThreadLocal每个线程有自己的存储区域。自身的数据被修改时,不会影响其他的线程

代码

例1

package cn.hanquan.test;/** 每个线程有自己的存储区域。自身的数据被修改时,不会影响其他的线程*/
public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 5);public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());threadLocal.set(-100);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());new Thread(() -> {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());threadLocal.set(2);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());}).start();}
}
main初始->5
main后来->-100
Thread-0初始->5
Thread-0后来->2

例2

需要注意threadLocal.get()的上下文,确定其代表的是哪一个线程

package cn.hanquan.test;/** 每个线程有自己的存储区域。自身的数据被修改时,不会影响其他的线程*/
public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 5);public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());threadLocal.set(-100);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());for (int i = 0; i < 5; i++) {new Thread(new myRun()).start();}}public static class myRun implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "初始为->" + threadLocal.get());threadLocal.set(threadLocal.get() - 2);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());}}
}
main初始->5
main后来->-100
Thread-0初始为->5
Thread-1初始为->5
Thread-0后来->3
Thread-2初始为->5
Thread-1后来->3
Thread-2后来->3
Thread-3初始为->5
Thread-3后来->3
Thread-4初始为->5
Thread-4后来->3

我的理解是:每一个Thread线程都有一个自己的独立threadLocal,可以更改其中的数据的时候,保证其他线程的threadLocal数据不会被修改。但是这有什么意义吗…不知道哪里能用得到?

InheritableThreadLocal

  • 可以继承的ThreadLocal

InheritableThreadLocal继承上下文环境的数据,复制一份给子线程(而非共享),相当于线程自己的局部变量

(1)不继承代码示例

package cn.hanquan.test;/** 不继承*/
public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 5);public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());threadLocal.set(-100);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());new Thread(() -> {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());}).start();}
}

(2)继承代码示例

package cn.hanquan.test;/** InheritableThreadLocal继承上下文环境的数据,复制一份给子线程*/
public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());threadLocal.set(20);System.out.println(Thread.currentThread().getName() + "后来->" + threadLocal.get());new Thread(() -> {System.out.println(Thread.currentThread().getName() + "初始->" + threadLocal.get());}).start();}
}
main初始->null
main后来->20
Thread-0初始->20

CAS

CAS是乐观锁的一种实现:比较并交换

先和原来的值比较。如果原来的值没动过,则交换。如果原来的值被改动过,交换失败。返回false。

效率高,是硬件级别的操作。也可以做到数据的共享。

Atomic原子性的操作都是使用可CAS的思想。

示例代码

【Java多线程】高级主题:定时调度、quartz、指令重排、volatile、ThreadLocal相关推荐

  1. java多线程高级:JUC

    文章目录 java多线程高级:JUC 1 多线程锁 1.1 传统synchronized 1.2 Lock接口 1.3 Synchronized和Lock的区别 2生产者和消费者问题 2.1 Sync ...

  2. Java并发编程(五)JVM指令重排

    我是不是学了一门假的java...... 引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果.. ...

  3. [19/04/12-星期五] 多线程_任务定时调度(Timer、Timetask和QUARTZ)

    一.Timer和Timetask 通过Timer和Timetask,我们可以实现定时启动某个线程. java.util.Timer 在这种实现方式中,Timer类作用是类似闹钟的功能,也就是定时或者每 ...

  4. JVM从入门到精通(三):热加载的实现原理,Java内存模型,缓存行,指令重排,合并写技术等

    上节回顾:类加载机制 双亲委派机制 parent只是一个成员变量,不是继承关系. 上节课的遗留问题 parent是怎么指定的? 手动指定parent: 双亲委派机制可以被打破吗? 双亲委派机制是在Cl ...

  5. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  6. Java多线程发展简史

    摘自: http://www.raychase.net/698 这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的Knowledge Sharing的一个整理,我希望能对Java从 ...

  7. [转] Java多线程发展简史

    这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的Knowledge Sharing的一个整理,我希望能对Java从第一个版本开始,在多线程编程方面的大事件和发展脉络有一个描述,并 ...

  8. Java多线程_1_Java内存模型_内存模型的3大特性

    Java内存模型: 内存分布情况及其关系: 主内存:Java内存模型规定所有的变量都保存在主内存中 工作内存:每个线程都有自己的工作内存,保存了该线程使用到的变量的主内存副本拷贝 主内存与工作内存的关 ...

  9. Java 多线程发展简史

    历史热门文章: 可以和面试官聊半个小时的volatile原理 Java中七个潜在的内存泄露风险,你知道几个? JDK 16新特性一览 啥?用了并行流还更慢了 InnoDB自增原理都搞不清楚,还怎么CR ...

最新文章

  1. lzma打包exe_Web 项目打包EXE
  2. C# 读写excel 用于导入数据库 批量导入导出excel
  3. Django在settings.py设置安装软件路径,遇到 'Settings' object is not subscriptable报错
  4. python解释器用什么写的_用 Python 从零开始写一个简单的解释器(3)
  5. 白板机器学习笔记 P22-P27 PCA降维
  6. 结合源码探讨Android距离传感器亮灭屏机制
  7. 一些牛人博客,值得收藏和学习
  8. 微正指纹识别算法MZFinger5.0
  9. 使用realsense t265测试svo2.0视觉里程计
  10. 「京东白条」的数据架构进化之路!
  11. ARM嵌入式核心板介绍
  12. Kotlin GreenDao
  13. 在云端管理您的所有身份(AAD)-第一部分
  14. 手把手带你撸一个校园APP(五):新闻中心模块
  15. Druid监控页面配置reset-enable的说明
  16. 记录一次京东面试吧,面试的是虚拟平台的经验.
  17. 2012回家过年:西安火车站遭遇碰瓷
  18. js单行代码------对象
  19. 少年,我看你骨骼惊奇,必是练武奇才,将来维护宇宙正义
  20. 图片分类-python

热门文章

  1. 安装翻译_【现象】面对日益增多的外国人 日本安装远程翻译设施
  2. 云计算具有什么平台_究竟什么是云计算?
  3. CSTrackV2解读
  4. 进程隐藏与进程保护(SSDT Hook 实现)(二)
  5. 漫游Kafka实现篇之分布式
  6. TCP长连接,短连接
  7. live555 源码分析:子会话 SDP 行生成
  8. 网骗欺诈?网络裸奔?都是因为 HTTP?
  9. 面试官:说说你对高性能秒杀系统的设计思考?
  10. 软件开发提效哪有那么容易,都是坑啊~