Java多線程四

1. Java內存模型

  在java中,所有實例域、靜態域和數組元素存儲在堆內存中,堆內存在線程之間共享(本文使用“共享變量”這個術語代指實例域,靜態域和數組元素)。局部變量(Local variables),方法定義參數(java語言規範稱之爲formal method parameters)和異常處理器參數(exception handler parameters)不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響。Java線程之間的通信由Java內存模型(JMM)控制,JMM決定一個線程對共享變量的寫入何時對另一個線程可見。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其他的硬件和編譯器優化。Java內存模型的抽象示意圖如下: 
      這裏寫圖片描述 
  下面通過簡單的案例分析。需求:多個線程獨立的操作變量sharedData,每個線程都可修改、獲得該變量。現實現每個線程單獨修改該變量,且更改的值只能在本線程內可見。

2. static方式實現

  我們知道static變量保存在堆內存中,可以被多個線程所共享。將所要共享的變量用static修飾:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 利用static實現線程間數據的共享</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> sharedData;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">staticShareValuable</span>() {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; i++) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Thread(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {
            @Override
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程範圍內修改共享變量</span>
                sharedData = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Random().nextInt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>);
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ModelA().<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span>();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ModelB().<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span>();
            }
        }).start();
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程的A模塊</span>
class ModelA {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">get</span>(){
        System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ModelA from "</span> + Thread.currentThread().getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 線程 "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" get data :"</span> + sharedData);
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程的B模塊</span>
class ModelB {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">get</span>(){
        System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ModelB from "</span> + Thread.currentThread().getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 線程 "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" get data :"</span> + sharedData);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>

  運行輸出:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ModelA <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">37</span>
ModelA <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">37</span>
ModelB <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">37</span>
ModelB <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">37</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

  由結果可知,static這種方式並不能實現線程單獨修改該變量,且更改的值只能在本線程內可見。其實這是顯然的,只是爲了說明:我們在多線程中使用static共享數據的時候一定要考慮這個問題!

3. Map方式模擬ThreadLocal基本原理

  將數據保存在Map集合當中,將當前的Thread實例作爲key,當前線程操作的變量作value,這樣就實現了每個線程獨立的操作變量。即線程操作數據的隔離。

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 模擬ThreadLocal的實現</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Map<Thread, Integer> context = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HashMap<Thread, Integer>();
<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
 *  每個線程獨立的實現更改sharedData,更改的值只能在本線程內可見
 *  利用傳統的static不能實現!
 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">mapShareValuable</span>() {

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; i++) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Thread(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {
            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程範圍內修改共享變量</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> copySharedData = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Random().nextInt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>);
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// map集合中放入key-value</span>
                context.put(Thread.currentThread(), copySharedData);
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ModelA().get();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ModelB().get();
            }
        }).start();
    }

}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程的A模塊</span>
class ModelA {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">get</span>(){
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// map集合中根據key(當前線程實例),取出當前線程所要操作的值</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> sharedData = context.get(Thread.currentThread());
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ModelA from "</span> + Thread.currentThread().getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 線程 "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" get data :"</span> + sharedData);
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 線程的B模塊</span>
class ModelB {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">get</span>(){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> sharedData = context.get(Thread.currentThread());
        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ModelB from "</span> + Thread.currentThread().getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 線程 "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" get data :"</span> + sharedData);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li></ul>

  運行輸出:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ModelA <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">61</span>
ModelA <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">33</span>
ModelB <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">61</span>
ModelB <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> Thread-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> 線程  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> data :<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">33</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

  由運行結果可以看出:Thread-0線程的模塊A和B獲得的數據爲Thread-0線程所修改的數據,兩個線程單獨修改變量,且更改的值只能在本線程內可見。其實這就是ThreadLocal簡單原理(只是key值不同,ThreadLocal內部的ThreadLocalMap(a customized hash map)對象,key爲ThreadLocal對象)。

4. ThreadLocal

  ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。 
  當使用ThreadLocal維護變量時,ThreadLocal爲每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。如果共享的變量有多個,可以將其封裝成對象,放入ThreadLocal中。例如Struts2的ActionContext需要保存當前請求線程的request、response,param,application以及action等等。下面的案例簡單模擬了Struts2的ActionContext功能。作爲上下文封裝當前線程的請求Request操作、響應Response,在Action中可通過ActionContext獲取這些對象。

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
 * 模擬Struts2的ActionContext
 * Struts2的ActionContext需要保存當前請求線程的request、response,param,application以及action等等。
 *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @author</span> markliu
 *
 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ThreadLocalTest</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 模擬兩次請求</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>; i++) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Thread(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {

                <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 以下代碼模擬Tomcat封裝請求信息等並綁定到對應線程</span>
                    Request request = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Request();
                    request.setRequestMsg(Thread.currentThread().getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程請求HelloWorld.action資源"</span>);
                    Response response = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Response();
                    response.setResponseMsg(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"向"</span> + Thread.currentThread().getName()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程"</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"返回資源"</span>);
                    ActionContext context = ActionContext.getContext();
                    context.setRequest(request);
                    context.setResponse(response);

                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 調用Action的方法</span>
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloWorldAction().execute();
                }
            }).start();
        }
    }

}

class HelloWorldAction {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> String <span class="hljs-title" style="box-sizing: border-box;">execute</span>() {
        ActionContext context = ActionContext.getContext();
        System.out.println(Thread.currentThread().getName()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程在"</span> + 
                <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Action中獲取的請求信息:"</span> + context.getRequest().getRequestMsg() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-->"</span> +
                <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Action中獲取的響應信息信息:"</span> + context.getResponse().getResponseMsg());
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"success"</span>;
    }
}
<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
 * 由於保存的數據有多個,需要多個ThreadLocal,可以
 * 將需要保存的request、response等信息封裝成一個上下文對象
 *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @author</span> markliu
 *
 */</span>
class ActionContext {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> ThreadLocal<ActionContext> actionContext = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ThreadLocal<ActionContext>(); 
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 封裝實際的request,response等信息</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Map<String, Object> context = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HashMap<String, Object>();

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> String REQUEST = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.xxx.request"</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> String RESPONSE = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.xxx.response"</span>;

    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * 獲取當前線程所對應的ActionContext
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span>
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> ActionContext <span class="hljs-title" style="box-sizing: border-box;">getContext</span>() {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 從ThreadLocal中獲取當前線程對應的上下文對象</span>
        ActionContext instance = actionContext.get();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(instance == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>){ <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果首次請求,爲null</span>
            instance = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ActionContext();
            actionContext.set(instance);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> instance;
    }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 從ThreadLocal移除當前線程的相關聯的上下文對象</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">remove</span>() {
        actionContext.remove();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setRequest</span>(Request request) {
        context.put(REQUEST, request);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Request <span class="hljs-title" style="box-sizing: border-box;">getRequest</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (Request) context.get(REQUEST);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setResponse</span>(Response response) {
        context.put(RESPONSE, response);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Response <span class="hljs-title" style="box-sizing: border-box;">getResponse</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (Response) context.get(RESPONSE);
    }
}

class Request {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> String requestMsg;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> String <span class="hljs-title" style="box-sizing: border-box;">getRequestMsg</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> requestMsg;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setRequestMsg</span>(String requestMsg) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.requestMsg = requestMsg;
    }
}

class Response {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> String responseMsg;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> String <span class="hljs-title" style="box-sizing: border-box;">getResponseMsg</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> responseMsg;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setResponseMsg</span>(String responseMsg) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.responseMsg = responseMsg;
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li></ul>

  運行結果如下: 
    這裏寫圖片描述 
  由此可見,實現了不同的線程分別處理各自線程範圍內的Request和Response。 
注意: 
1. 上面案例的ThreadLocal實例只有一個。 
2. 當線程結束時,要調用ThreadLocal的remove()方法,從thread-local variable中移除。

發佈了39 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章