熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java多線程開發之線程局部變量的使用

2013-11-23 19:43:18  來源: Java高級技術 
    一概述
   
    現在多核時代多線程開發越來越重要了多線程相比於多進程有諸多優勢(當然也有諸多劣勢)在早期C的庫中有許多函數是線程不安全的因為內部用到了靜態變量比如char *strtok(char *s const char *delim) 該函數內部就有一個靜態指針如果多個線程同時調用此函數時可能就會出現奇怪的結果當然也不是我們所想要的現在LINUX對此函數功能有一個線程安全版本的接口char *strtok_r(char *s const char *delim char **ptrptr)這就避免了多個線程同時訪問的沖突問題其實如果保持 strtok()/ 接口不變同時還要保證線程安全還有一個解決辦法那就是采用線程局部變量
   
    使用線程局部變量有兩種使用方式一個稍微麻煩些一個比較簡單下面一一做個介紹(以LINUX為例)
   
    二線程局部變量的使用
   
    比較麻煩些的使用方法用到的函數主要有三個pthread_once(pthread_once_t* void (*init_routine)(void)) pthread_key_create()/ pthread_setspecific()/ pthread_getspecific()/其中 pthread_once 可以保證在整個進程空間init_routine函數僅被調用一次(它解決了多線程環境中使得互斥量和初始化代碼都僅被初始化一次的問題)pthread_key_create 的參數之一指一個析構函數指針當某個線程終止時該析構函數將被調用並用對於一個進程內的給定鍵該函數只能被調用一次pthread_sespecific 和 pthread_getspecific 用來存放和獲取與一個鍵關聯的值例子如下
   
    pthread_key_t key;
   
    pthread_once_t once = PTHREAD_ONCE_INIT;
   
    static void destructor(void *ptr)
   
    {
   
    free(ptr)
   
    }
   
    void init_once(void)
   
    {
   
    pthread_key_create(&key destructor)
   
    }
   
    static void *get_buf(void)
   
    {
   
    pthread_once(&once init_once)
   
    if ((ptr = pthread_getspecific(key)) == NULL) {
   
    ptr = malloc(
   
    pthread_setspecific(key ptr)
   
    }
   
    return (ptr)
   
    }
   
    static void *thread_fn(void *arg)
   
    {
   
    char *ptr = (char*) get_buf()
   
    sprintf(ptr hello world
   
    printf(》%s\n ptr)
   
    return (NULL)
   
    }
   
    void test(void)
   
    {
   
    int   i n = ;
   
    pthread_t tids[];
   
    for (i = ; i < n; i++) {
   
    pthread_create(&tids[i] NULL thread_fn NULL)
   
    }
   
    for (i = ; i < n; i++) {
   
    pthread_join(&tids[i] NULL)
   
    }
   
    }
   
    另外還有一個更加簡單使用線程局部變量的方法__thread 修飾符 (在WIN平台下需要用 __declspec(thread) 修飾符WIN的東東總得要多寫幾筆呵呵)於是上述代碼可以修改如下
   
    static void *get_buf(void)
   
    {
   
    static __thread void *ptr = malloc(
   
    return (ptr)
   
    }
   
    static void *thread_fn(void *arg)
   
    {
   
    char *ptr = (char*) get_buf()
   
    sprintf(ptr hello world
   
    printf(》%s\n ptr)
   
    return (NULL)
   
    }
   
    void test(void)
   
    {
   
    int   i n = ;
   
    pthread_t tids[];
   
    for (i = ; i < n; i++) {
   
    pthread_create(&tids[i] NULL thread_fn NULL)


   
    }
   
    for (i = ; i < n; i++) {
   
    pthread_join(&tids[i] NULL)
   
    }
   
    }
   
    看到沒有這段代碼比前面一個簡單許多但卻有一個問題它存在內存洩露問題因為當線程退出時各個線程分配的動態內存(ptr = malloc()) 並沒有被釋放
   
    三用ACL線程接口操作線程局部變量
   
    為了解決上述問題ACL庫中實現了線程局部變量的簡單釋放功能acl_pthread_atexit_add(void *arg void (*free_callback)(void*))修改上述代碼如下
   
    static void free_fn(void *ptr)
   
    {
   
    free(ptr)
   
    }
   
    static void *get_buf(void)
   
    {
   
    static __thread void *ptr = malloc(
   
    acl_pthread_atexit_add(ptr free_fn)
   
    return (ptr)
   
    }
   
    static void *thread_fn(void *arg)
   
    {
   
    char *ptr = (char*) get_buf()
   
    sprintf(ptr hello world
   
    printf(》%s\n ptr)
   
    return (NULL)
   
    }
   
    void test(void)
   
    {
   
    int   i n = ;
   
    pthread_t tids[];
   
    for (i = ; i < n; i++) {
   
    acl_pthread_create(&tids[i] NULL thread_fn NULL)
   
    }
   
    for (i = ; i < n; i++) {
   
    acl_pthread_join(&tids[i] NULL)
   
    }
   
    }
   
    ok 一切問題得到解決細心的讀者會發現 pthread_create pthread_join 前面都加了前綴 acl_ 這是因為 ACL庫對線程庫進行了封裝以適應不同平台下(UNIXWIN)下的使用這個例子是跨平台的WIN下同樣可用


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27360.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.