一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 生產者消費者模型ThreadLocal原理及實例詳解

生產者消費者模型ThreadLocal原理及實例詳解

2020-09-28 00:29愛笑的berg Java教程

這篇文章主要介紹了生產者消費者模型ThreadLocal原理及實例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

1、生產者消費者模型作用和示例如下:

1)通過平衡生產者的生產能力和消費者的消費能力來提升整個系統的運行效率 ,這是生產者消費者模型最重要的作用

2)解耦,這是生產者消費者模型附帶的作用,解耦意味著生產者和消費者之間的聯系少,聯系越少越可以獨自發展而不需要收到相互的制約

備注:對于生產者消費者模型的理解將在并發隊列BlockingQueue章節進行說明,本章不做詳細介紹。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package threadLearning.productCustomerModel;
/*
  wait/notify 機制:以資源為例,生產者生產一個資源,通知消費者就消費掉一個資源,生產者繼續生產資源,消費者消費資源,以此循環。
  wait():使一個線程處于等待(阻塞)狀態,并且釋放所持有的對象的鎖;
  sleep(): 使一個正在運行的線程處于睡眠狀態, 是一個靜態方法, 調用此方法要處理 InterruptedException 異常;
  notify():喚醒一個處于等待狀態的線程,當然在調用此方法的時候,并不能確切的喚醒某一個等待狀態的線程而是由 JVM 確定喚醒哪個線程,而且與優先級無關;
  notityAll():喚醒所有處于等待狀態的線程,該方法并不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態;
備注:java 5 通過 Lock 接口提供了顯示的鎖機制,Lock 接口中定義了加鎖(lock()方法)和解鎖(unLock()方法),增強了多線程編程的靈活性及對線程的協調
*/
 
//資源對象:包含商品名屬性;提供生產和消費方法;
class Resource {
  private String name;//商品名
  private int count = 0;
  private boolean flag = false;//生產或者消費的控制開關
  public synchronized void set(String name) {
    // 生產資源
    while (flag) {
      try {
        // 線程等待。消費者消費資源
        wait();
      } catch (Exception e) {
      }
    }
    this.name = name + "---" + count++;
    System.out.println(Thread.currentThread().getName() + "...生產者..."
        + this.name);
    flag = true;
    // 喚醒等待中的消費者
    this.notifyAll();//喚醒在此對象監視器上等待的所有線程  Object.notifyAll()
  }
 
  public synchronized void out() {
    // 消費資源
    while (!flag) {
      // 線程等待,生產者生產資源
      try {
        wait();
      } catch (Exception e) {
      }
    }
    System.out.println(Thread.currentThread().getName() + "...消費者..."
        + this.name);
    flag = false;
    // 喚醒生產者,生產資源
    this.notifyAll();
  }
}
 
// 生產者
class Producer implements Runnable {
  private Resource res;
 
  Producer(Resource res) {
    this.res = res;
  }
 
  // 生產者生產資源
  public void run() {
    while (true) {
      res.set("商品");
    }
  }
}
 
// 消費者消費資源
class Consumer implements Runnable {
  private Resource res;
 
  Consumer(Resource res) {
    this.res = res;
  }
 
  public void run() {
    while (true) {
      res.out();
    }
  }
}
public class ProducerConsumerDemo {
  public static void main(String[] args) {
    Resource r = new Resource();
    Producer pro = new Producer(r);
    Consumer con = new Consumer(r);
    Thread t1 = new Thread(pro);
    Thread t2 = new Thread(con);
    t1.start();
    t2.start();
  }
}

2、ThreadLocal

  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;

總的來說ThreadLocal就是一種以 空間換時間 的做法,在每個Thread里面維護了一個以開地址法實現的ThreadLocal.ThreadLocalMap,把數據進行隔離,數據不共享,自然就沒有線程安全方面的問題了。

示例1:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package threadLearning.thredLocal;
/*
1、該類提供了線程局部 (thread-local) 變量。這些變量不同于它們的普通對應物,因為訪問某個變量(通過其 get 或 set 方法)的每個線程都有自己的局部變量,它獨立于變量的初始化副本。ThreadLocal 實例通常是類中的 private static 字段,它們希望將狀態與某一個線程(例如:用戶 ID 或事務 ID)相關聯。
2、ThreadLocal的使用
(1) 在關聯數據類中創建 private static ThreadLocal在下面的類中,私有靜態 ThreadLocal 實例(serialNum)為調用該類的靜態 SerialNum.get() 方法的每個線程維護了一個“序列號”,該方法將返回當前線程的序列號。(線程的序列號是在第一次調用 SerialNum.get() 時分配的,并在后續調用中不會更改。
每個線程都保持對其線程局部變量副本的隱式引用,只要線程是活動的并且 ThreadLocal 實例是可訪問的;在線程消失之后,其線程局部實例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用)。
*/
public class SerialNum {
  private static int nextSerialNum = 3;
  private static ThreadLocal serialNum = new ThreadLocal() {//創建一個線程本地變量
    protected synchronized Object initialValue() {
      return new Integer(nextSerialNum++);
    }
  };
 
  public static int get() {
    return ((Integer) (serialNum.get())).intValue();
  }
  
  public static void main(String args[]){
    Thread thead1=new Thread(new Runnable() {
      public void run() {
        System.out.println("thead1-->"+get());       
      }
    });
    Thread thead2=new Thread(new Runnable() {
      public void run() {
        System.out.println("thead2-->"+get());       
      }
    });
    thead1.start();
    thead2.start();
    /*
  同一個Thread啟動第二次會報錯java.lang.IllegalThreadStateExceptionThread報錯的原因,并不是說,重新啟動Thread導致的,
而是因為共用一個Thread導致的,因為,如果是實現Runnable的類,每次啟動線程都需要new Thread(Runnable).start(),這就使得線
程沒有被共用。
    while(true){
      thead2.start();
      
    }
    */
  }
}

運行結果:

thead1-->3
thead2-->4

示例2:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package threadLearning.thredLocal;
class Res {
  // 生成序列號共享變量
  public static Integer count = 0;
  public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
    // 覆蓋返回此線程局部變量的當前線程的“初始值”方法
    @Override
    protected Integer initialValue() {
      return 0;
    };
  };
 
  public Integer getNum() {
    int count = threadLocal.get() + 1;//get() 該方法返回當前線程所對應的線程局部變量
    threadLocal.set(count);//將此線程局部變量的當前線程副本中的值設置為指定值
    return count;
  }
}
 
public class ThreadLocaDemo2 extends Thread {
  private Res res;
 
  public ThreadLocaDemo2(Res res) {
    this.res = res;
  }
 
  @Override
  public void run() {
    for (int i = 0; i < 3; i++) {
      System.out.println(Thread.currentThread().getName() + "---" + "i---" + i + "--num:" + res.getNum());
    }
 
  }
 
  public static void main(String[] args) {
    Res res = new Res();
    ThreadLocaDemo2 threadLocaDemo1 = new ThreadLocaDemo2(res);
    ThreadLocaDemo2 threadLocaDemo2 = new ThreadLocaDemo2(res);
    ThreadLocaDemo2 threadLocaDemo3 = new ThreadLocaDemo2(res);
    threadLocaDemo1.start();
    threadLocaDemo2.start();
    threadLocaDemo3.start();
  }
}

運行結果:

?
1
2
3
4
5
6
7
8
9
Thread-1---i---0--num:1
Thread-2---i---0--num:1
Thread-0---i---0--num:1
Thread-2---i---1--num:2
Thread-1---i---1--num:2
Thread-2---i---2--num:3
Thread-0---i---1--num:2
Thread-1---i---2--num:3
Thread-0---i---2--num:3

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.cnblogs.com/jiarui-zjb/p/9622003.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲精美视频 | 荷兰精品女人性hd | japanese秘书丝袜 | 亚洲日韩中文字幕一区 | 91制片厂果冻传媒首页 | 暖暖视频高清图片免费完整版 | 美国大片成人性网 | 暖暖 免费 高清 中文 日本 | 接吻吃胸摸下面啪啪教程 | 韩国美女豪爽一级毛片 | 国产精品日本亚洲777 | 91精品国产一区 | 色婷婷激婷婷深爱五月老司机 | 极品主播的慰在线播放 | 久久青青草视频在线观 | 肉蒲在线观看 | 久久亚洲精品AV成人无 | tube4欧美4| 果冻传媒 天美 麻豆 | 欧洲破处 | 秋霞午夜视频在线观看 | 国产成人综合网 | 麻豆最新地址 | 好大好硬好深好爽gif图 | 12345国产精品高清在线 | 日韩 国产 欧美 精品 在线 | 大陆黄色片 | 亚洲国产精品久久久久久 | www黄| 校园纯肉H教室第一次 | 日韩在线视频在线 | 国产3344视频在线观看免费 | 国产一二在线观看视频网站 | 久久久久国产一级毛片高清片 | 亚洲免费高清视频 | 亚洲AV久久无码精品九九软件 | 草逼的视频 | 日本人作爰啪啪全过程 | 亚洲欧美日韩精品高清 | 亚洲国产日韩成人综合天堂 | a∨在线观看 |