1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Java多线程】高级主题:定时调度 quartz 指令重排 volatile ThreadLocal

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

时间:2022-08-08 04:22:37

相关推荐

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

定时调度

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初始->5main后来->-100Thread-0初始->5Thread-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初始->5main后来->-100Thread-0初始为->5Thread-1初始为->5Thread-0后来->3Thread-2初始为->5Thread-1后来->3Thread-2后来->3Thread-3初始为->5Thread-3后来->3Thread-4初始为->5Thread-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初始->nullmain后来->20Thread-0初始->20

CAS

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

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

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

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

示例代码

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。