2.2synchronized同步語句塊

来源:http://www.cnblogs.com/lilinzhiyu/archive/2017/12/06/7994275.html
-Advertisement-
Play Games

使用synchronized雖然能夠避免不同步的現象出現,但是也會出現弊端,比如代碼執行時間過長,那麼其他線程就必須等待該線程執行完畢釋放鎖之後才能拿到鎖。 面對這種問題可以使用同步代碼塊來解決。 2.2.1synchronized方法的弊端: 任務類: 工具類: 線程代碼1: 線程代碼2: 執行代 ...


使用synchronized雖然能夠避免不同步的現象出現,但是也會出現弊端,比如代碼執行時間過長,那麼其他線程就必須等待該線程執行完畢釋放鎖之後才能拿到鎖。

面對這種問題可以使用同步代碼塊來解決。

2.2.1synchronized方法的弊端:

任務類:

public class Task {
    private String getData1;
    private String getData2;
    synchronized public void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            getData1 = "長時間處理任務後從遠程返回的值1 threadName = "
                    + Thread.currentThread().getName();
            getData2 = "長時間處理任務後從遠程返回的值2 threadName = "
                    + Thread.currentThread().getName();
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

工具類:

public class CommonUtils {
    public static long beginTime1;
    public static long endTime1;
    public static long beginTime2;
    public static long endTime2;
}

線程代碼1:

public class Thread1 extends Thread {
    private Task task;
    public Thread1(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        CommonUtils.beginTime1 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime1 = System.currentTimeMillis();
    }
}

線程代碼2:

public class Thread2 extends Thread {
    private Task task;
    public Thread2(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        CommonUtils.beginTime2 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2 = System.currentTimeMillis();
    }
}

執行代碼:

public class Main {
    public static void main(String[] args) {
        Task task = new Task();
        Thread1 thread1 = new Thread1(task);
        thread1.start();
        Thread2 thread2 = new Thread2(task);
        thread2.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime = CommonUtils.beginTime1;
        if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
            beginTime = CommonUtils.beginTime2;
        }
        long endTime = CommonUtils.endTime1;
        if (CommonUtils.endTime2 > CommonUtils.endTime1) {
            endTime = CommonUtils.endTime2;
        }

        System.out.println("耗時: " + (endTime - beginTime) / 1000);

    }
}

執行結果:

從結果看這樣運行一段代碼耗時嚴重,解決這樣的問題可以使用synchronized同步代碼塊。

2.2.2synchronized同步代碼塊的使用:

兩個線程同時訪問同一個對象的synchronized(this)同步代碼塊時,在代碼運行期間只能有一個線程執行該段代碼塊,另一個線程必須等待當前線程完成執行才能夠執行該段代碼。

模塊業務類:

public class ObjectService {
    public void serviceMethod() {
        try {
            synchronized (this) {
                System.out.println("begin time = " + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("end time = " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

線程代碼1:

public class Thread3 extends Thread {
    private ObjectService objectService;
    public Thread3(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void run() {
        objectService.serviceMethod();
    }
}

線程代碼2:

public class Thread4 extends Thread {
    private ObjectService objectService;
    public Thread4(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void run() {
        objectService.serviceMethod();
    }
}

執行代碼:

public class Main {
    public static void main(String[] args) {
        ObjectService objectService = new ObjectService();
        Thread3 thread3 = new Thread3(objectService);
        thread3.setName("a");
        thread3.start();
        Thread4 thread4 = new Thread4(objectService);
        thread4.setName("b");
        thread4.start();
    }
}

執行結果:

這樣使用同步代碼塊,並沒有使代碼的效率提高,執行的效果還是同步執行的。下麵的示例中解決synchronized同步代碼塊執行效率低的問題。

2.2.3用同步代碼塊解決同步方法的弊端:

任務類:

public class DoLongTimeTask1 {
    private String getData1;
    private String getData2;
    public void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            String privateData1 = "長時間處理任務後從後臺遠程返回的值1 threadName = "
                    + Thread.currentThread().getName();
            String privateData2 = "長時間處理任務後從後臺遠程返回的值2 threadName = "
                    + Thread.currentThread().getName();
            synchronized (this) {
                getData1 = privateData1;
                getData2 = privateData2;
            }
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

線程代碼1:

public class Thread1 extends Thread {
    private Task task;
    public Thread1(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        CommonUtils.beginTime1 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime1 = System.currentTimeMillis();
    }
}

線程代碼2:

public class Thread2 extends Thread {
    private Task task;
    public Thread2(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        CommonUtils.beginTime2 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2 = System.currentTimeMillis();
    }
}

執行代碼:

public class Main {
    public static void main(String[] args) {
        Task task = new Task();
        Thread1 thread1 = new Thread1(task);
        thread1.start();
        Thread2 thread2 = new Thread2(task);
        thread2.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime = CommonUtils.beginTime1;
        if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
            beginTime = CommonUtils.beginTime2;
        }
        long endTime = CommonUtils.endTime1;
        if (CommonUtils.endTime2 > CommonUtils.endTime1) {
            endTime = CommonUtils.endTime2;
        }

        System.out.println("耗時: " + (endTime - beginTime) / 1000);

    }
}

執行結果:

從上述可知當一個線程訪問object中的synchronized同步代碼塊時,其他線程可以訪問該object對象中非synchronized(this)同步代碼塊的內容。

時間縮短,且運行效率加快,而且能夠保持synchronized是同步的且當前線程持有鎖。下麵的示例進行驗證。

2.2.4一半非同步,一半同步:

事先說明:不在synchronized塊中的代碼使非同步的,在synchronized中的代碼是同步的。

任務代碼:

public class Task1 {
    public void doLongTimeTask() {
        for (int i = 0; i < 100; i++) {
            System.out.println("nosynchronized  threadName = " + Thread.currentThread().getName() + "  i = " + (i + 1));
        }
        System.out.println("");
        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                System.out.println("synchronized  threadName = " + Thread.currentThread().getName() + "  i = " + (i + 1));
            }
        }
    }
}

線程代碼1:

public class Task1 {
    public void doLongTimeTask() {
        for (int i = 0; i < 100; i++) {
            System.out.println("nosynchronized  threadName = " + Thread.currentThread().getName() + "  i = " + (i + 1));
        }
        System.out.println("");
        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                System.out.println("synchronized  threadName = " + Thread.currentThread().getName() + "  i = " + (i + 1));
            }
        }
    }
}

線程代碼2:

public class Thread6 extends Thread {
    private Task1 task;
    public Thread6(Task1 task) {
        this.task = task;
    }

    @Override
    public void run() {
        task.doLongTimeTask();
    }
}

執行代碼:

public class Main {
    public static void main(String[] args) {
        Task1 task = new Task1();
        Thread5 thread5 = new Thread5(task);
        thread5.start();
        Thread6 thread6 = new Thread6(task);
        thread6.start();

    }
}

執行結果(左邊為非同步,右邊為同步):

可以看出在同步代碼塊中的代碼是同步運行的,而在非同步代碼塊中的代碼是非同步運行的。

2.2.5synchronized代碼塊間的同步性:

若一個線程訪問了object的一個synchronized(this)同步代碼塊時,其他線程對同一個object中所有的其他synchronized(this)同步代碼塊的訪問將被阻塞。

這個現象表明瞭:synchronized使用的是一個對象監視器。

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ASCII表中的有些字元是列印不出來的,那麼怎樣表示這些無法列印的字元呢? C提供了3種表示方法. 一: 直接使用ASCII碼 二: 使用特殊的符號序列, 即轉義字元. 三: C90支持使用十六進位形式表示字元常量.(在這種形式中,反斜杠後跟一個x或X,再加上1到3位十六進位數字) 轉義字元 ASC ...
  • 1.在eclipse中用maven創建項目,右鍵new>>Maven Project 2.點擊next繼續 3.點擊next繼續,選擇maven-archetype-webapp, 4.點擊next繼續,填寫Group id和Artifact id, Version預設,Package可以不填 5. ...
  • 父類和子類的轉換 向上轉型: Father f1 = new son(); 向下轉型: son f2= (son)f1; 代碼如下: 父類 子類 主程式 ...
  • 這是因為切換成了java面板的原因 因為之前有切換到過 java project 項目,所以才轉到了這個面板,之後如果不手動改即便是用javaee也會是這個面板,因而用起來不方便 解決方法: 切換到javaee面板就好了 這樣的話用起來控制台等方面就更加靈活了 ...
  • 最近在學習多線程,題目源自 MoreWindows先生的 《秒殺多線程第一篇》(http://blog.csdn.net/morewindows/article/details/7392749) 題目摘錄: 第五題(Google面試題) 有四個線程1、2、3、4。線程1的功能就是輸出1,線程2的功能 ...
  • 創建類 實例化對象 form = 類名(instance=obj,data=request.POST) instance傳的是已有的對象(在頁面中顯示預設值)data傳的是從頁面返回過來的值(用戶輸入的值 ,用來驗證) form.is_valid() #驗證 form.save #將數據保存至資料庫 ...
  • 一、ModelForm的介紹 應用場景: - ModelForm - 中小型應用程式。因為ModelForm是依賴於models的 - Form - 大型應用程式 * 註意事項: 二、表結構 三、基於Form組件的添加和編輯 添加:這隻是單表的添加 編輯:單表的編輯 具體基於Form組件實現的一對多 ...
  • Modelform組件 Modelform就是model和from兩者結合起來的。它既有驗證,又有資料庫的操作 Modelform組件: Modelform註意事項: 1、類 示列(增刪改查): url: from django.conf.urls import url from django.co ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...