多線程之間通訊JDK1.5-Lock

来源:https://www.cnblogs.com/losemyfuture/archive/2018/07/24/9357907.html
-Advertisement-
Play Games

synchronized:代碼開始上鎖,代碼結束時釋放鎖;內置鎖、自動化的、效率低、擴展性不高(不夠靈活); JDK1.5併發包Lock鎖 保證線程安全問題,屬於手動擋,手動開始上鎖,手動釋放鎖,靈活性高; Lock 介面與 synchronized 關鍵字的區別 Lock 介面可以嘗試非阻塞地獲取 ...


synchronized:代碼開始上鎖,代碼結束時釋放鎖;內置鎖、自動化的、效率低、擴展性不高(不夠靈活);

JDK1.5併發包Lock鎖 --保證線程安全問題,屬於手動擋,手動開始上鎖,手動釋放鎖,靈活性高;

Lock 介面與 synchronized 關鍵字的區別
Lock 介面可以嘗試非阻塞地獲取鎖 當前線程嘗試獲取鎖。如果這一時刻鎖沒有被其他線程獲取到,則成功獲取並持有鎖。
Lock 介面能被中斷地獲取鎖 與 synchronized 不同,獲取到鎖的線程能夠響應中斷,當獲取到的鎖的線程被中斷時,中斷異常將會被拋出,同時鎖會被釋放。

Lock 介面在指定的截止時間之前獲取鎖,如果截止時間到了依舊無法獲取鎖,則返回。

Lock用法:

Lock寫法
Lock lock = new ReentrantLock();
lock.lock();
try{
//可能會出現線程安全的操作
}finally{
//一定在finally中釋放鎖
//也不能把獲取鎖在try中進行,因為有可能在獲取鎖的時候拋出異常
lock.ublock();
}
class Res{
public String username;
public String sex;
//true 生產者等待,消費者可消費 false生產者可以生產,消費者不可消費
public boolean flag=false;
Lock lock=new ReentrantLock();
}
class Out extends Thread{
Res res;
Condition newCondition;

public Out(Res res,Condition newCondition){
    this.res=res;
    this.newCondition=newCondition;
}
@Override
public void run() {
    //寫操作
    int count=0;
    while (true){
        try{//防止異常後不釋放鎖
            res.lock.lock();
            if(res.flag){
               newCondition.await();//讓當前線程從運行變為阻塞,並且釋放所的資源
            }
            if(count==0){//偶數
                res.username="小明";
                res.sex="男";
            } else {//奇數
                res.username="小紅";
                res.sex="女";
            }
            count=(count+1)%2;
            res.flag=true;
            newCondition.signal();
        } catch (Exception e){
        } finally {
            res.lock.unlock();
        }
    }
}

}
class Input extends Thread{
Res res;
Condition newCondition;
public Input(Res res,Condition newCondition){
this.res=res;
this.newCondition=newCondition;
}

@Override
public void run() {
    while (true){
        try{
            res.lock.lock();
            if(!res.flag){
                newCondition.await();//讓當前線程從運行變為阻塞,並且釋放所的資源
            }
            System.out.println(res.username+","+res.sex);
            res.flag=false;
            newCondition.signal();
        } catch (Exception e){
        } finally {
            res.lock.unlock();
        }
    }
}

}
public class LockDemo {
public static void main(String[] args) {
Res res = new Res();
Condition condition=res.lock.newCondition();
Out out = new Out(res,condition);
Input input = new Input(res,condition);
out.start();
input.start();
}

}

Condition用法:

Condition condition = lock.newCondition();
res. condition.await(); 類似wait
res. Condition. Signal() 類似notify
多線程併發(Thread)操作同一個資源---------網站併發(多個請求同時訪問一臺服務)

停止線程

停止線程思路

  1. 使用退出標誌,使線程正常退出,也就是當run方法完成後線程終止。
2.  使用stop方法強行終止線程;這個方法不推薦使用,因為stop和suspend、resume一樣,也可能發生不可預料的結果(沒執行完就終止沒有記錄上次執行點,並且不可恢復,不論你當前什麼狀況都給你停掉)。



3.  使用interrupt方法中斷線程。

那麼怎麼停止線程比較合適呢?或者說怎麼設計一種停止線程的方式?

class StopThreadDemo extends Thread{
private volatile boolean flag=true;

@Override
public void run() {
    System.out.println("子線程開始執行......");
    while (flag){

    }
    System.out.println("子線程執行結束......");
}
public void stopThread(){
    this.flag=false;
}

}
public class StopThread {
public static void main(String[] args) throws InterruptedException {
StopThreadDemo stopThreadDemo=new StopThreadDemo();
stopThreadDemo.start();
for (int i = 0; i < 10; i++) {
System.out.println("我是主線程,i:"+i);
Thread.sleep(1000);
if(i==6)
stopThreadDemo.stopThread();
}
}
}

我是主線程,i:0
子線程開始執行......
我是主線程,i:1
我是主線程,i:2
我是主線程,i:3
我是主線程,i:4
我是主線程,i:5
我是主線程,i:6
我是主線程,i:7
子線程執行結束......
我是主線程,i:8
我是主線程,i:9

class StopThreadDemo extends Thread{
private volatile boolean flag=true;

@Override
public synchronized void run() {
    System.out.println("子線程開始執行......");
    while (flag){
        try {
            wait();
        } catch (InterruptedException e) {

// e.printStackTrace();
stopThread();
}
}
System.out.println("子線程執行結束......");
}
public void stopThread(){
this.flag=false;
}
}
public class StopThread {
public static void main(String[] args) throws InterruptedException {
StopThreadDemo stopThreadDemo=new StopThreadDemo();
stopThreadDemo.start();
for (int i = 0; i < 10; i++) {
System.out.println("我是主線程,i:"+i);
Thread.sleep(1000);
if(i==6) {
//當前等待線程直接拋出異常
stopThreadDemo.interrupt();
// stopThreadDemo.stopThread();
}
}
}
}
以上兩種方式都可以。。。
可以看到這是一種停止線程的方式

ThreadLocal
ThreadLocal提高一個線程的局部變數,訪問某個線程擁有自己局部變數。

線程1和線程2各自操作自己的副本count,互相影響。

當使用ThreadLocal維護變數時,ThreadLocal為每個使用該變數的線程提供獨立的變數副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。

ThreadLocal的介面方法

ThreadLocal類介面很簡單,只有4個方法,我們先來瞭解一下:

void set(Object value)設置當前線程的線程局部變數的值。
public Object get()該方法返回當前線程所對應的線程局部變數。
public void remove()將當前線程局部變數的值刪除,目的是為了減少記憶體的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變數將自動被垃圾回收,所以顯式調用該方法清除線程的局部變數並不是必須的操作,但它可以加快記憶體回收的速度。
protected Object initialValue()返回該線程局部變數的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,線上程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的預設實現直接返回一個null。
案例:創建三個線程,每個線程生成自己獨立序列號。

class ResNum{
public int count=0;
public static ThreadLocal

public String getNumber(){
    count=threadLocal.get()+1;
    threadLocal.set(count);

// count=count+1;
return count+"";
}
}
class LocalThreadDemo extends Thread{
private ResNum resNum;
public LocalThreadDemo(ResNum resNum){
this.resNum=resNum;
}

@Override
public void run() {
    for (int i = 0; i < 3; i++) {
        System.out.println(getName()+","+resNum.getNumber());
    }
}

}
public class ThreadLocalDemo {
public static void main(String[] args) {
ResNum resNum1=new ResNum();
// ResNum resNum2=new ResNum();
// ResNum resNum3=new ResNum();
LocalThreadDemo t1=new LocalThreadDemo(resNum1);
LocalThreadDemo t2=new LocalThreadDemo(resNum1);
LocalThreadDemo t3=new LocalThreadDemo(resNum1);
t1.start();
t2.start();
t3.start();
}
}


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

-Advertisement-
Play Games
更多相關文章
  • 1、應用架構為什麼要分層 先看應用不分層有什麼缺點: 代碼不夠清晰,難以閱讀。 代碼職責不明,難以擴展。 代碼錯綜複雜,難以維護。 代碼沒做分工,難以組織。 分層有什麼特點: 按業務功能進行分層。 層次關係良好,上層依賴下層,下層支撐上層,下層不能訪問上層。 每一層都能保持獨立。 一般應用使用三層架 ...
  • 最近很長時間沒寫博客了,其實這個博客寫過一半,中間有事耽擱了,就沒繼續。主要是給別人做了一個小系統,及維護碼雲上的代碼庫。同居的日子也占了我很多時間。 最近也是煩,欠了7W,各種煩事。所以可想寫個博客靜靜心。 在面向對象中關註的焦點是對象空間,對象與對象的聯繫還是通過保存引用(相當於路),來走到其空 ...
  • 目的是為了可維護、可復用、可擴展、靈活性好 以四則運算為例: 先有個父類運算類: ...
  • 1、什麼是 對象-關係映射 對象-關係映射(Object Relational Mapping,簡稱ORM,對象關係映射)是一種為瞭解決面向對象與關係資料庫存在的互不匹配的現象的技術。 簡單的說,ORM是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中。本質上就是將數 ...
  • 軟敏捷開發框架V7.0全新升級功能更全,運行更穩定。新版本增加了多語言,首頁動態設置、移動端代碼生成以及大量實用組件。 IM、工作流、代碼生成器也進行了重構,用起來好得不得了! 還等什麼,快去官網看看吧! 主要更新的功能: 新增 1.多語言功能; 2.代碼生成器模版; a.可編輯列表代碼生成器(Ex ...
  • 九、位元組流與字元流 9.1 IO的分類 輸入流 :把數據從其他設備上讀取到記憶體中的流。 輸出流 :把數據從記憶體 中寫出到其他設備上的流。 位元組流 :以位元組為單位,讀寫數據的流。 字元流 :以字元為單位,讀寫數據的流。 輸入流 輸出流 位元組流 位元組輸入流 InputStream 位元組輸出流 Outpu ...
  • 題意 。。。求最短路 Sol 前幾天寫dijkstra的時候沒打vis標記居然A了,然後天真的我就以為Dijkstra不用打標記。 事實上dijkstra真的不用打標記,只不過會被卡成SPFA的複雜度 ...
  • 關鍵點: 一、 二、 beans 配置 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...