【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級說這個代碼會發生指令重排,但是我測試沒有發生重排…
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初始->20CAS
CAS是樂觀鎖的一種實現:比較并交換
先和原來的值比較。如果原來的值沒動過,則交換。如果原來的值被改動過,交換失敗。返回false。
效率高,是硬件級別的操作。也可以做到數據的共享。
Atomic原子性的操作都是使用可CAS的思想。
示例代碼
總結
以上是生活随笔為你收集整理的【Java多线程】高级主题:定时调度、quartz、指令重排、volatile、ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java多线程】生产者消费者问题
- 下一篇: 【Java网络编程(一)】IP地址、端口