Dowemo
0 0 0 0

A threadlocalvariable isn't a thread, but a local variable of thread, and it may be named more easily.

When a variable is used to maintain a variable, the ds0 provides a separate copy of the variable for each thread using that variable, so each thread can change the

From a thread 's point of view, the target variable is the local variable of the thread, which is the meaning of"local"in the class name.

Threadlocal interface method

A class interface is simple, with only 4 methods, and we're going to know:

voidset(Object value)

To set the value of the thread local variable for the current thread.

publicObjectget()

This method retur & the thread local variable corresponding to the current thread.

publicvoidremove()

Deletes the value of the current thread local variable, and aims to reduce memory footprint, which is a new method for jdk 5.0. It's important to note that when the thread ends, the local variable that should be thread is automatically reclaimed, so explicitly calling the method to clear the local local variable isn't the necessary action, but it speeds up the memory recovery speed.

protected Object initialValue()

Returns the initial value of the local variable, which is a protected method, obviously designed to allow subclasses to override. This method is a delayed invocation method that executes when the thread 1 calls get ( ) or set ( object ), and executes only 1 times. The default implementation in the directly returns a null.

Note that in jdk5. 0, has already supported generics, and the class name of the class has been changed. Api methods are also adjusted, and the new version of the api method is void set ( t value ), t get ( ), and t _ initialvalue ( ).

Ds0 maintenance variables

How does the turtle maintain a copy of the variable for each thread. In fact, the idea is simple: There's a map in the ds0 class to store a copy of each thread 's variable, and the key of the element in the map is a thread object, and a copy of the We can provide a simple version of the implementation:

publicclass SimpleThreadLocal {
 private Map valueMap = Collections.synchronizedMap(new HashMap());
 publicvoidset(Object newValue) {
 valueMap.put(Thread.currentThread(), newValue);//①键为线程对象,值为本线程的变量副本 }
 public Object get() {
 Thread currentThread = Thread.currentThread();
 Object o = valueMap.get(currentThread);//②返回本线程对应的变量if (o == null &&!valueMap.containsKey(currentThread)) {
 //③如果在Map中不存在,放到Map中保存起来。 o = initialValue();
 valueMap.put(currentThread, o);
 }
 return o;
 }
 publicvoidremove() {
 valueMap.remove(Thread.currentThread());
 }
 public Object initialValue() {
 returnnull;
 }
}

Although the version of the above code is relatively straightforward, it's similar to that provided by the jdk in the implementation idea.

A theadlocal I & tance

Below, we know how to use a concrete example with a specific example.

publicclassSequenceNumber {//①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值privatestatic ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
 public Integer initialValue(){
 return0;
 }
 };
 //②获取下一个序列值publicintgetNextNum(){
 seqNum.set(seqNum.get()+1);
 return seqNum.get();
 }
 publicstaticvoidmain(String[] args)
 {
 SequenceNumber sn = new SequenceNumber();
 //③ 3个线程共享sn,各自产生序列号 TestClient t1 = new TestClient(sn);
 TestClient t2 = new TestClient(sn);
 TestClient t3 = new TestClient(sn);
 t1.start();
 t2.start();
 t3.start();
 }
 privatestaticclassTestClientextendsThread {private SequenceNumber sn;
 publicTestClient(SequenceNumber sn) {
 this.sn = sn;
 }
 publicvoidrun()
 {
 for (int i = 0; i <3; i++) {//④每个线程打出3个序列值 System.out.println("thread["+Thread.currentThread().getName()+
 "] sn["+sn.getNextNum()+"]");
 }
 }
}

Typically, we define the subclasses of the ds0 by means of an anonymous inner class, providing the initial variable value, as shown in the example. A testclient thread generates a set of serial numbe & where we generate 3 testclient, which share the same sequencenumber I & tance. Run the above code to output the following results on the co & ole:

thread[Thread-2]sn[1]thread[Thread-0]sn[1]thread[Thread-1]sn[1]thread[Thread-2]sn[2]thread[Thread-0]sn[2]thread[Thread-1]sn[2]thread[Thread-2]sn[3]thread[Thread-0]sn[3]thread[Thread-1]sn[3]

Look at the results of the output, we found that each thread generated the sequence number, but they didn't interfere with each other, but they generated a separate serial number, because we provided a separate copy of each thread by the mat, because we provided a separate copy for each thread.

The role of the threadlocal.

Threadlocal isn't used to solve access problems for shared objects, typically by the object that's used by the threadlocal ( ) to the thread in the thread, and other threads aren't required to access it and are accessed by other threads. There are different objects in each thread to ask. ( note that this is just a"general situation". If the object in a threadlocal is shared with the same object in the thread, the access to the same shared object is the same shared object.

1. Provides methods for saving objects: Each thread has its own ThreadLocalMap class object, which allows you to keep its own objects in one of them, each of which can be properly accessed by the thread.

2. The convenient object access method to avoid paramete &: A common threadlocal I tance as key, saving references to different objects to ThreadLocalMap of different threads, and then executing that object at the end of the thread through the get ( ) method of the, avoids the trouble of passing this object as a parameter, avoiding the trouble of passing this object as a parameter.

Unde & tanding the copy of the variables mentioned in the ds0

"when a variable is used to maintain a variable, -- provides a separate copy of the variable for each thread that uses that variable,"isn't implemented through the mixin. Set ( ), but each thread uses the"new object"( or copy ) action to create a copy of the object, so each thread is taken out of its own map, so that the is used as the key for the map ( which is used as the key for map ). (.

If the object in the get. Set ( ) is the same object that's shared by multithreaded, then. ( ) gets or that the shared object itself is --, or there's a concurrent access problem.

/* 
 * 如果ThreadLocal.set()进去的是一个多线程共享对象,那么Thread.get()获取的还是这个共享对象本身-----并不是该共享对象的副本。 
 * 假如:其中其中一个线程对这个共享对象内容作了修改,那么将会反映到其它线程获取的共享对象中----所以说 ThreadLocal还是有并发访问问题的! 
 */publicclassTestimplementsRunnable 
{ 
 private ThreadLocal<Person> threadLocal = new ThreadLocal<Person>(); 
 private Person person; 
 publicTest(Person person) 
 { 
 this.person = person; 
 } 
 publicstaticvoidmain(String[] args) throws InterruptedException 
 { 
 //多线程共享的对象  Person sharePerson = new Person(110,"Sone"); 
 Test test = new Test(sharePerson); 
 System.out.println("sharePerson原始内容:"+sharePerson); 
 Thread th = new Thread(test); 
 th.start(); 
 th.join(); 
 //通过ThreadLocal获取对象  Person localPerson = test.getPerson(); 
 System.out.println("判断localPerson与sharePerson的引用是否一致:"+(localPerson==localPerson)); 
 System.out.println("sharePerson被改动之后的内容:"+sharePerson); 
 } 
 @Override 
 publicvoidrun() 
 { 
 String threadName = Thread.currentThread().getName(); 
 System.out.println(threadName+":Get a copy of the variable and change!!!"); 
 Person p = getPerson(); 
 p.setId(741741); 
 p.setName("Boy"); 
 } 
 public Person getPerson(){ 
 Person p = (Person)threadLocal.get(); 
 if (p==null) 
 { 
 p= this.person; 
 //set():进去的是多线程共享的对象  threadLocal.set(p); 
 } 
 return p; 
 }

General steps used by

1, in classes, such as the ThreadDemo class, create a ds0 object threadxxx that holds the object that requires isolation between threads.

2, in the ThreadDemo class, create a method getXXX ( ) that gets the data to be isolated. ( ) is determined in the method, and if the mixin object is null, the new ( ) an object that isolated the access type should be used and cast to the type to apply.

3, in the run ( ) method of the ThreadDemo class, get the data to operate through the getXXX ( ) method, which guarantees that each thread corresponds to a data object.

/**
 * 学生
 */publicclassStudent {privateint age = 0; //年龄publicintgetAge() {
 returnthis.age;
 }
 publicvoidsetAge(int age) {
 this.age = age;
 }
}/**
 * 多线程下测试程序
 */publicclassThreadLocalDemoimplementsRunnable {//创建线程局部变量studentLocal,在后面你会发现用来保存Student对象privatefinalstatic ThreadLocal studentLocal = new ThreadLocal();
 publicstaticvoidmain(String[] agrs) {
 ThreadLocalDemo td = new ThreadLocalDemo();
 Thread t1 = new Thread(td, "a");
 Thread t2 = new Thread(td, "b");
 t1.start();
 t2.start();
 }
 publicvoidrun() {
 accessStudent();
 }
 /**
 * 示例业务方法,用来测试
 */publicvoidaccessStudent() {
 //获取当前线程的名字 String currentThreadName = Thread.currentThread().getName();
 System.out.println(currentThreadName + " is running!");
 //产生一个随机数并打印 Random random = new Random();
 int age = random.nextInt(100);
 System.out.println("thread" + currentThreadName + " set age to:" + age);
 //获取一个Student对象,并将随机数年龄插入到对象属性中 Student student = getStudent();
 student.setAge(age);
 System.out.println("thread" + currentThreadName + " first read age is:" + student.getAge());
 try {
 Thread.sleep(500);
 }
 catch (InterruptedException ex) {
 ex.printStackTrace();
 }
 System.out.println("thread" + currentThreadName + " second read age is:" + student.getAge());
 }
 protected Student getStudent() {
 //获取本地线程变量并强制转换为Student类型 Student student = (Student) studentLocal.get();
 //线程首次执行此方法的时候,studentLocal.get()肯定为nullif (student == null) {
 //创建一个Student对象,并保存到本地线程变量studentLocal中 student = new Student();
 studentLocal.set(student);
 }
 return student;
 }
}

Run results:

a isrunning! 
thread a set age to:76 
b isrunning! 
thread b set age to:27 
thread a firstread age is:76 
thread b firstread age is:27 
thread a secondread age is:76 
thread b secondread age is:27

You can see a, b, two thread age is identical at different times at different times. This program can't only realize concurrent concurrency, but also keep the data security.

Here's an example of the following: Simulate a game, randomly set an integer for [ 1, 10 ], then each player to guess the number, each player knows the result of another player, and see who.

This game is really boring, but it's just possible to take each player as a thread, and then use ds0 to record the history of the player 's guess so that it's easy to unde.

Judge: used to set the target numbers and judge the results.

Player: per player as a thread, multiple player parallel to try guess, thread termination when guessing.

Class attempt: classes with mixin fields and guessing action static methods that are used to save a guessing number.

Record: save history data structure with a list field.

In order to be compatible with various types of data, the actual content is an object that passes through set and get, as shown in attempt 's getrecord ( ).

At run time, each player thread is to call the attemp. Guess ( ) method, and then work with the same mixin variable history, but can save each thread 's own data, which is the role of the cla.

publicclass ThreadLocalTest {
 publicstaticvoidmain(String[] args) {
 Judge.prepare();
 new Player(1).start();
 new Player(2).start();
 new Player(3).start();
 }
}
class Judge {
 publicstaticint MAX_VALUE = 10;
 privatestaticint targetValue;
 publicstaticvoidprepare() {
 Random random = new Random();
 targetValue = random.nextInt(MAX_VALUE) + 1;
 }
 publicstatic boolean judge(intvalue) {
 returnvalue == targetValue;
 }
}
class Player extends Thread {
 privateint playerId;
 publicPlayer(int playerId) {
 this.playerId = playerId;
 }
 @Override
 publicvoidrun() {
 boolean success = false;
 while(!success) {
 intvalue = 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 {
 privatestatic ThreadLocal<Record> history = new ThreadLocal<Record>();
 publicstaticintguess(int maxValue) {
 Record record = getRecord();
 Random random = new Random();
 intvalue = 0;
 do {
 value = random.nextInt(maxValue) + 1;
 } while (record.contains(value));
 record.save(value);
 returnvalue;
 }
 publicstaticvoidreview(String info) {
 System.out.println(info + getRecord());
 }
 privatestatic 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>();;
 publicvoidsave(intvalue) {
 attemptList.add(value);
 }
 public boolean contains(intvalue) {
 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();
 }
}

Run results

Plyaer 2 Attempts 8and Failed
Plyaer 3 Attempts 6and Failed
Plyaer 1 Attempts 5and Failed
Plyaer 2 Attempts 7and Success
Plyaer 3 Attempts 9and Failed
Plyaer 1 Attempts 9and Failed
Plyaer 3 Attempts 2and Failed
Plyaer 1 Attempts 2and Failed
[IFNO] Plyaer 2 Completed by2 Times: 8, 7Plyaer 3 Attempts 4and Failed
Plyaer 1 Attempts 1and Failed
Plyaer 3 Attempts 5and Failed
Plyaer 1 Attempts 3and Failed
Plyaer 3 Attempts 1and Failed
Plyaer 1 Attempts 10and Failed
Plyaer 3 Attempts 8and Failed
Plyaer 1 Attempts 6and Failed
Plyaer 3 Attempts 7and Success
Plyaer 1 Attempts 4and Failed
[IFNO] Plyaer 3 Completed by8 Times: 6, 9, 2, 4, 5, 1, 8, 7Plyaer 1 Attempts 7and Success
[IFNO] Plyaer 1 Completed by9 Times: 5, 9, 2, 1, 3, 10, 6, 4, 7

Hreadlocal get ( )

For the principle of ds0, it can be seen from its get ( ) method.

public class ThreadLocal<T> {
 ... public T get() {
 Thread t = Thread.currentThread();
 ThreadLocalMap map = getMap(t);
 if (map!= null) {
 ThreadLocalMap.Entry e = map.getEntry(this);
 if (e!= null)
 return (T)e.value;
 }
 return setInitialValue();
 }
 ThreadLocalMap getMap(Thread t) {
 return t.threadLocals;
 }
 ...}

Execute get ( ) first, get the current thread, get the ThreadLocalMap - t, threadlocals in thread, and take the actual value as its own key. As you can see, the variable 's variable actually remains in thread, and the container is a map, which is used by thread, and how many entry.




Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs