java多線程之Thread-Specific Storage模式

一、Thread-Specific Storage模式

Specific是特定的意思,Storage模式是儲存櫃的意思,因爲所謂Thread-Specific Storage就是“每個線程特有的儲物櫃”“爲每個線程準備儲存空間”的意思。

Thread-Specific Storage模式是一種即使只有一個入口,也會在內部爲每個線程分配特有的儲存空間的模式。

二、關於java.lang.ThreadLocal類(就是儲物間)

將java.lang.ThreadLocal的實例當作一種集合可能會有助於理解它,也就是說ThreadLocal的實例會管理多個對象。

  • set方法

ThreadLocal類的set方法用戶將通過參數接收的實例與調用該方法的線程對應並存儲起來,這裏存儲的對象可以通過get方法獲取,set方法中沒有表示線程的參數,set方法會先查詢當前線程,然後以它作爲鍵來存儲實例。

調用set方法相當於將自己的行李放置到自己的存物櫃中。

  • get方法

ThreadLocal類的get方法用戶獲取與調用get方法的線程(當前線程)對應的實例,該線程之前通過set方法存儲的實例就是get方法的返回值,如果之前一次都還沒有調用過set方法,則get方法的返回值爲null。

與set方法一樣,get方法中也沒有表示線程的參數,因爲,get方法也會去查詢當前線程,即get方法會以當前線程自身作爲鍵去獲取對象。

調用get方法相當於從自己的儲物櫃中取出自己的行李。

public class ThreadLocal<T> {    //存儲    public void set(T value) {        ...    }     //獲取    public T get() {        ...    }    ...}

即通過ThreadLocal的T指定的類型就是set方法的參數的類型以及get方法的返回值的類型。

三、不使用Thread-Specific Storage模式示例程序

1.示例程序一覽表

類名 說明
Log.java 創建日誌的類
Main.java 測試示例程序的類

2.示例程序的類圖

img

3.Log類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson1;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:22
 * @Description:
 */
public class Log {
    /**
     * 是用於在名爲log.txt的文件中記錄程序運行記錄的類。
     * writer字段中保存的是用於寫文件的java.io.PrintWriter的實例。
     * println方法是用於將通過參數接收到的字符串寫入到文件中的方法。
     * close方法是用於關閉日誌文件的方法。
     */
    private static PrintWriter writer = null;

    //初始化writer字段
    static {
        try {
            writer = new PrintWriter(new FileWriter("log.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //寫日誌
    public static void println(String s) {
        writer.println(s);
    }

    //關閉日誌
    public static void close() {
        writer.println("===end of log===");
        writer.close();
    }
}

4.Main類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:22
 * @Description:
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("Begin");
        for (int i = 0; i < 10; i++) {
            Log.println("main: i = " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.close();
        System.out.println("End");
    }
}

5.運行結果

Begin
End //for循環中設置的等待時間是1s,這裏大約10s後顯示

6.文件內容

main: i = 0
main: i = 1
main: i = 2
main: i = 3
main: i = 4
main: i = 5
main: i = 6
main: i = 7
main: i = 8
main: i = 9
===end of log===

7.示例程序的Timethreads圖

img

四、使用Thread-Specific Storage模式示例程序

1.示例程序類的一覽表

類名 說明
TSLog.java 創建日誌的類(實例屬於各個線程所有)
Log.java 創建日誌的類(分配各個線程)
java.lang.ThreadLocal 分配線程特有的存儲空間的類
ClientThread.java 表示調用Log的線程的類
Main 測試示例程序的類

2.示例程序的類圖

img

3.TSLog類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class TSLog {
    private PrintWriter writer = null;

    //初始化writer字段
    public TSLog(String filename) {
        try {
            writer = new PrintWriter(new FileWriter(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //寫日誌
    public void println(String s) {
        writer.println(s);
    }

    //關閉日誌
    public void close() {
        writer.println("=== End of log ===");
        writer.close();
    }
}

4.Log類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

public class Log {
    private static final ThreadLocal<TSLog> tslogCollection = new ThreadLocal<TSLog>();

    //寫日誌
    public static void println(String s) {
        getTSLog().println(s);
    }

    //關閉日誌
    public static void close() {
        getTSLog().close();
    }

    //獲取線程特有的日誌
    private static TSLog getTSLog() {
        TSLog tsLog = tslogCollection.get();

        //如果該線程是第一次調用本方法,就新生成並註冊一個日誌
        if (tsLog == null) {
            tsLog = new TSLog(Thread.currentThread().getName() + "-log.txt");
            tslogCollection.set(tsLog);
        }
        return tsLog;
    }
}

5.ClientThread類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:22
 * @Description:
 */
public class ClientThread extends Thread {
    public ClientThread(String name) {
        super(name);
    }

    public void run() {
        System.out.println(getName() + " Begin");
        for (int i = 0; i < 10; i++) {
            Log.println(getName() + " i = " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.close();
        System.out.println(getName() + " End");
    }
}

6.Main類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:27
 * @Description:
 */
public class Main {
    public static void main(String[] args) {
        new ClientThread("Steve Nash").start();
        new ClientThread("Michael Jordan").start();
        new ClientThread("Ronaldo").start();
    }
}

7.運行結果

Steve Nash Begin
Michael Jordan Begin
Ronaldo Begin
Michael Jordan End
Steve Nash End
Ronaldo End
//這裏分別創建了Michael Jordan-log.txt、Ronaldo-log.txt、Steve Nash-log.txt

8.生成文件內容

//如Michael Jordan-log.txt
Michael Jordan i = 0
Michael Jordan i = 1
Michael Jordan i = 2
Michael Jordan i = 3
Michael Jordan i = 4
Michael Jordan i = 5
Michael Jordan i = 6
Michael Jordan i = 7
Michael Jordan i = 8
Michael Jordan i = 9
=== End of log ===

9.示例程序的Timethreads圖

img

五、Thread-Specific Storage模式中角色

1.Client(委託者)

Client角色將處理委託給TSObjectProxy角色,一個TSObjectProxy角色會被多個Client角色使用,是示例程序2中的ClientThread類。

2.TSObjectProxy(線程持有的對象的代理人)

TSObjectProxy角色會執行多個Client角色委託給的處理。是示例程序2中的Log類。

3.TSObjectCollection(線程持有的對象的集合)

TSObjectCollection角色有一張Client角色與TSObject角色之間的對應表。是示例程序2中的java.lang.ThreadLocal類。

4.TSObject(線程持有的對象)

TSObject角色中保存着線程持有的信息,是示例程序2中的TSLog類。

5.Thread-Specific Storage模式的類圖

img

6.Thread-Specific Storage模式的時序圖

imgjava多線程之Thread-Specific Storage模式

2018-02-24 14:25:27 更多

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。本文鏈接:https://blog.csdn.net/smartdt/article/details/79361099

一、Thread-Specific Storage模式

Specific是特定的意思,Storage模式是儲存櫃的意思,因爲所謂Thread-Specific Storage就是“每個線程特有的儲物櫃”“爲每個線程準備儲存空間”的意思。

Thread-Specific Storage模式是一種即使只有一個入口,也會在內部爲每個線程分配特有的儲存空間的模式。

二、關於java.lang.ThreadLocal類(就是儲物間)

將java.lang.ThreadLocal的實例當作一種集合可能會有助於理解它,也就是說ThreadLocal的實例會管理多個對象。

  • set方法

ThreadLocal類的set方法用戶將通過參數接收的實例與調用該方法的線程對應並存儲起來,這裏存儲的對象可以通過get方法獲取,set方法中沒有表示線程的參數,set方法會先查詢當前線程,然後以它作爲鍵來存儲實例。

調用set方法相當於將自己的行李放置到自己的存物櫃中。

  • get方法

ThreadLocal類的get方法用戶獲取與調用get方法的線程(當前線程)對應的實例,該線程之前通過set方法存儲的實例就是get方法的返回值,如果之前一次都還沒有調用過set方法,則get方法的返回值爲null。

與set方法一樣,get方法中也沒有表示線程的參數,因爲,get方法也會去查詢當前線程,即get方法會以當前線程自身作爲鍵去獲取對象。

調用get方法相當於從自己的儲物櫃中取出自己的行李。

public class ThreadLocal<T> {    //存儲    public void set(T value) {        ...    }     //獲取    public T get() {        ...    }    ...}

即通過ThreadLocal的T指定的類型就是set方法的參數的類型以及get方法的返回值的類型。

三、不使用Thread-Specific Storage模式示例程序

1.示例程序一覽表

類名 說明
Log.java 創建日誌的類
Main.java 測試示例程序的類

2.示例程序的類圖

img

3.Log類

public class Log {    /**     * 是用於在名爲log.txt的文件中記錄程序運行記錄的類。     * writer字段中保存的是用於寫文件的java.io.PrintWriter的實例。     * println方法是用於將通過參數接收到的字符串寫入到文件中的方法。     * close方法是用於關閉日誌文件的方法。     */    private static PrintWriter writer = null;     //初始化writer字段    static {        try {            writer = new PrintWriter(new FileWriter("log.txt"));        } catch (IOException e) {            e.printStackTrace();        }    }     //寫日誌    public static void println(String s) {        writer.println(s);    }     //關閉日誌    public static void close() {        writer.println("===end of log===");        writer.close();    }}

4.Main類

public class Main {    public static void main(String[] args) {        System.out.println("Begin");        for (int i = 0; i < 10; i++) {            Log.println("main: i = " + i);            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        Log.close();        System.out.println("End");    }}

5.運行結果

BeginEnd //for循環中設置的等待時間是1s,這裏大約10s後顯示

6.文件內容

main: i = 0main: i = 1main: i = 2main: i = 3main: i = 4main: i = 5main: i = 6main: i = 7main: i = 8main: i = 9===end of log===

7.示例程序的Timethreads圖

img

四、使用Thread-Specific Storage模式示例程序

1.示例程序類的一覽表

類名 說明
TSLog.java 創建日誌的類(實例屬於各個線程所有)
Log.java 創建日誌的類(分配各個線程)
java.lang.ThreadLocal 分配線程特有的存儲空間的類
ClientThread.java 表示調用Log的線程的類
Main 測試示例程序的類

2.示例程序的類圖

img

3.TSLog類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class TSLog {
    private PrintWriter writer = null;

    //初始化writer字段
    public TSLog(String filename) {
        try {
            writer = new PrintWriter(new FileWriter(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //寫日誌
    public void println(String s) {
        writer.println(s);
    }

    //關閉日誌
    public void close() {
        writer.println("=== End of log ===");
        writer.close();
    }
}

4.Log類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

public class Log {
    private static final ThreadLocal<TSLog> tslogCollection = new ThreadLocal<TSLog>();

    //寫日誌
    public static void println(String s) {
        getTSLog().println(s);
    }

    //關閉日誌
    public static void close() {
        getTSLog().close();
    }

    //獲取線程特有的日誌
    private static TSLog getTSLog() {
        TSLog tsLog = tslogCollection.get();

        //如果該線程是第一次調用本方法,就新生成並註冊一個日誌
        if (tsLog == null) {
            tsLog = new TSLog(Thread.currentThread().getName() + "-log.txt");
            tslogCollection.set(tsLog);
        }
        return tsLog;
    }
}

5.ClientThread類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:22
 * @Description:
 */
public class ClientThread extends Thread {
    public ClientThread(String name) {
        super(name);
    }

    public void run() {
        System.out.println(getName() + " Begin");
        for (int i = 0; i < 10; i++) {
            Log.println(getName() + " i = " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.close();
        System.out.println(getName() + " End");
    }
}

6.Main類

package com.viagra.Thread_Specific_Storage_Pattern.Lesson2;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 20:27
 * @Description:
 */
public class Main {
    public static void main(String[] args) {
        new ClientThread("Steve Nash").start();
        new ClientThread("Michael Jordan").start();
        new ClientThread("Ronaldo").start();
    }
}

7.運行結果

Steve Nash Begin
Michael Jordan Begin
Ronaldo Begin
Michael Jordan End
Steve Nash End
Ronaldo End
//這裏分別創建了Michael Jordan-log.txt、Ronaldo-log.txt、Steve Nash-log.txt

8.生成文件內容

//如Michael Jordan-log.txt
Michael Jordan i = 0
Michael Jordan i = 1
Michael Jordan i = 2
Michael Jordan i = 3
Michael Jordan i = 4
Michael Jordan i = 5
Michael Jordan i = 6
Michael Jordan i = 7
Michael Jordan i = 8
Michael Jordan i = 9
=== End of log ===

9.示例程序的Timethreads圖

img

五、Thread-Specific Storage模式中角色

1.Client(委託者)

Client角色將處理委託給TSObjectProxy角色,一個TSObjectProxy角色會被多個Client角色使用,是示例程序2中的ClientThread類。

2.TSObjectProxy(線程持有的對象的代理人)

TSObjectProxy角色會執行多個Client角色委託給的處理。是示例程序2中的Log類。

3.TSObjectCollection(線程持有的對象的集合)

TSObjectCollection角色有一張Client角色與TSObject角色之間的對應表。是示例程序2中的java.lang.ThreadLocal類。

4.TSObject(線程持有的對象)

TSObject角色中保存着線程持有的信息,是示例程序2中的TSLog類。

5.Thread-Specific Storage模式的類圖

img

6.Thread-Specific Storage模式的時序圖

img

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章