ThreadLocal使用

转载http://gaofeihang.blog.163.com/blog/static/84508285201293071940706/

ThreadLocal的含义是Thread Local Variable,它可以声明一个字段,使得不同的线程访问这个字段时,获取的都是不同的副本,互不影响。

ThreadLocal的作用和在每个Thread类声明一个字段相同,那么什么时候使用它呢?还是在编写一些框架时,因为这时你无法预先定义Thread类。其中一个典型的用法是调用一个静态方法,这个静态方法会操作一个ThreadLocal变量,而不同的线程去调用时,访问的就是不同的副本。

下面通过这样一个例子来说明:模拟一个游戏,预先随机设定一个[1, 10]的整数,然后每个玩家去猜这个数字,每个玩家不知道其他玩家的猜测结果,看谁用最少的次数猜中这个数字。

这个游戏确实比较无聊,不过这里恰好可以把每个玩家作为一个线程,然后用ThreadLocal来记录玩家猜测的历史记录,这样就很容易理解ThreadLocal的作用。

Judge:用来设定目标数字以及判断猜测的结果。
Player:每个Player作为一个线程,多个Player并行地去尝试猜测,猜中时线程终止。
Attempt:具有ThreadLocal字段和猜测动作静态方法的类, ThreadLocal用于保存猜过的数字。
Record:保存历史记录的数据结构,有一个List<Integer>字段。

ThreadLocal为了可以兼容各种类型的数据,实际的内容是再通过set和get操作的对象,详见Attempt的getRecord()。
运行的时候,每个Player Thread都是去调用Attemp.guess()方法,进而操作同一个ThreadLocal变量history,但却可以保存每个线程自己的数据,这就是ThreadLocal的作用。
 
package test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ThreadLocalTest {
    public static void main(String[] args) {
        Judge.prepare();
        new Player(1).start();
        new Player(2).start();
        new Player(3).start();
    }
}

class Judge {
    public static int  MAX_VALUE = 10;
    private static int targetValue;

    public static void prepare() {
        Random random = new Random();
        targetValue = random.nextInt(MAX_VALUE) + 1;
    }

    public static boolean judge(int value) {
        return value == targetValue;
    }
}

class Player extends Thread {
    private int playerId;

    public Player(int playerId) {
        this.playerId = playerId;
    }

    @Override
    public void run() {
        boolean success = false;
        while (!success) {
            int value = Attempt.guess(Judge.MAX_VALUE);
            success = Judge.judge(value);
            System.out.println(String.format("Plyaer %s Attempts %s and %s", playerId, value,
                success ? " Success" : "Failed"));
        }
        Attempt.review(String.format("[IFNO] Plyaer %s Completed by ", playerId));
    }
}

class Attempt {
    private static ThreadLocal<Record> history = new ThreadLocal<Record>();

    public static int guess(int maxValue) {
        Record record = getRecord();
        Random random = new Random();
        int value = 0;
        do {
            value = random.nextInt(maxValue) + 1;
        } while (record.contains(value));
        record.save(value);
        return value;
    }

    public static void review(String info) {
        System.out.println(info + getRecord());
    }

    private static Record getRecord() {
        Record record = history.get();
        if (record == null) {
            record = new Record();
            history.set(record);
        }
        return record;
    }
}

class Record {
    private List<Integer> attemptList = new ArrayList<Integer>(); ;

    public void save(int value) {
        attemptList.add(value);
    }

    public boolean contains(int value) {
        return attemptList.contains(value);
    }

    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(attemptList.size() + " Times: ");
        int count = 1;
        for (Integer attempt : attemptList) {
            buffer.append(attempt);
            if (count < attemptList.size()) {
                buffer.append(", ");
                count++;
            }
        }
        return buffer.toString();
    }
}
 
运行结果
Plyaer 1 Attempts 4 and Failed
Plyaer 3 Attempts 4 and Failed
Plyaer 1 Attempts 1 and Failed
Plyaer 3 Attempts 7 and  Success
Plyaer 1 Attempts 9 and Failed
[IFNO] Plyaer 3 Completed by 2 Times: 4, 7
Plyaer 1 Attempts 7 and  Success
[IFNO] Plyaer 1 Completed by 4 Times: 4, 1, 9, 7
Plyaer 2 Attempts 8 and Failed
Plyaer 2 Attempts 7 and  Success
[IFNO] Plyaer 2 Completed by 2 Times: 8, 7
 
ThreadLocal原理主要是包含了Map,key为线程id, value是线程变量副本。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值