多線程之間通訊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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...