相关疑惑解决,java线程虚假唤醒等等问题
生活随笔
收集整理的這篇文章主要介紹了
相关疑惑解决,java线程虚假唤醒等等问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. System.out.println方法是線程安全的
之前一直疑惑為啥下面案例中的主線程中num = 1會對線程A可見,注意沒有加volatile修飾
class Test1{//public volatile static int num =0;public static int num =0;public static void main(String[] args) {new Thread(()->{while (num==0){System.out.println(Thread.currentThread().getName());}},"線程A").start();try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}num = 1;System.out.println(num);} }后來百度一下知道原來println()方法是線程安全的
//println方法的實現public void println(int x) {synchronized (this) {print(x);newLine();}}JMM關于Synchronized的兩條規定:
線程加鎖時,講清空工作內存中共享變量的值,從而使用共享變量是需要從主內存中重新讀取最新的值(加鎖與解鎖需要統一把鎖)
線程解鎖前,必須把共享變量的最新值刷新到主內存中;
2. 虛假喚醒
public class PcModel {public static void main(String[] args){SynResource synResource = new SynResource();new Thread(()->{try {for (int i = 0; i < 10; i++) {synResource.increment();}} catch (InterruptedException e) {e.printStackTrace();}},"生產者").start();new Thread(()->{try {for (int i = 0; i < 10; i++) {synResource.increment();}} catch (InterruptedException e) {e.printStackTrace();}},"生產者副本").start();new Thread(()->{try {for (int i = 0; i < 10; i++) {synResource.decrement();}} catch (InterruptedException e) {e.printStackTrace();}},"消費者").start();new Thread(()->{try {for (int i = 0; i < 10; i++) {synResource.decrement();}} catch (InterruptedException e) {e.printStackTrace();}},"消費者副本").start();} }class SynResource{volatile private int count =0;synchronized void increment() throws InterruptedException {if (count == 1){this.wait();}System.out.println(Thread.currentThread().getName() + "+ 1");count++;this.notifyAll();}synchronized void decrement() throws InterruptedException {if (count == 0){this.wait();}System.out.println(Thread.currentThread().getName() + "- 1");count--;this.notifyAll();} }上面是一個經典的生產者-消費者模型。當只有一個生產者和一個消費者時程序能正常運行,但如果按照上面的例子來運行。可以發現運行結果并不是我們所想要的結果。這是因為if語句執行完后會接著向下執行,即當線程被喚醒重新獲得鎖后會接著向下運行,這時就會產生虛假喚醒的問題了(生產者和生產者副本都運行至this.wait()),如果把if語句改成while就能避免此中現象產生。
3. ReadWriteLock
- 如果當前是寫鎖被占有了,只有當寫鎖的數據降為0時才認為釋放成功;否則失敗。因為只要有寫鎖,那么除了占有寫鎖的那個線程,其他線程即不可以獲得讀鎖,也不能獲得寫鎖
- 如果當前是讀鎖被占有了,那么只有在寫鎖的個數為0時才認為釋放成功。因為一旦有寫鎖,別的任何線程都不應該再獲得讀鎖了,除了獲得寫鎖的那個線程。
4. static synchronized 修飾的方法中
當前鎖對象是 類.calss對象 注意與非靜態方法的區別
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的相关疑惑解决,java线程虚假唤醒等等问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于java中::语法的理解
- 下一篇: linux 常用命令 (firewall