java线程(二)
线程范围变量
我们知道线程在cpu上的使用权并不是长时间的,因为计算机的cpu只有一个,而在计算上运行的进程有很多,线程就更不用说了,所以cpu只能通过调度来上多个线程轮流占用cpu资源运行,且为了保障多个进程能够同时运行。cpu只能通过频繁调度线程来是的每个线程在几乎同一时间内都能得到cpu的使用权来执行代码来保证程序能够正常运行,所以cpu的调度频率是很快的。那么问题来了。如下代码:
1 package cn.wz.traditional.wf; 2 3 import javafx.scene.chart.PieChart; 4 5 /** 6 * Created by WangZhe on 2017/5/4. 7 */ 8 public class ThraedLocalTest { 9 public static void main(String[] args) { 10 new Thread(new Runnable() { 11 public void run() { 12 A.age=5; 13 A.age+=10; 14 System.out.println(A.age); 15 } 16 }).start(); 17 18 new Thread(new Runnable() { 19 public void run() { 20 A.age=7; 21 } 22 }).start(); 23 } 24 static class A{ 25 static Integer age=5; 26 private Integer data; 27 public A(Integer data){ 28 this.data=data; 29 } 30 public void sayHi(){ 31 data+=10; 32 System.out.println(data); 33 34 } 35 public void sayHello(){ 36 data=5; 37 } 38 } 39 }
上面这段代码创建了两个线程,第一个线程将a的原始值加10后输出,第二个线程将a赋值为7,但在不改变代码的前提下多次执行后发现这段代码出现了两种运行结果。如图所示。
这种问题正是由于cpu调度线程所引起的,当其结果为15时使我们所预期的效果,那怎样来确保其结果和我们预期的效果一致呢?废话不多说了直接上代码
package cn.wz.traditional.wf; import javafx.scene.chart.PieChart; import java.util.HashMap; import java.util.Map; /** * Created by WangZhe on 2017/5/4. */ public class ThraedLocalTest { public static void main(String[] args) { new Thread(new Runnable() { public void run() { A a=new A(5); a.sayHi(5); } }).start(); new Thread(new Runnable() { public void run() { A a=new A(5); a.sayHello(); } }).start(); } static class A{ static Map<String,Integer> ages=new HashMap<String, Integer>();//创建一个键值集合一线程id为key值来存放线程范围的变量 private Integer data; public A(Integer data){ this.data=data; } public void sayHi(Integer age){ ages.put(String.valueOf(Thread.currentThread().getId()),age); Integer data= ages.get(String.valueOf(Thread.currentThread().getId())); data+=10; ages.put(String.valueOf(Thread.currentThread().getId()),data); System.out.println(ages.get(String.valueOf(Thread.currentThread().getId()))); } public void sayHello(){ ages.put(String.valueOf(Thread.currentThread().getId()),7); } } }
在之前代码的基础上增加一个map集合来保存线程范围的变量数据,以当前线程的id为key值来确保每次取到的值都是当前线程的值。但是这种方法出现了大量的冗余代码,每次取值赋值都很费劲,其实Java API提供了Threadlocal类来保存线程范围的变量,下面是使用Threadlocal类之后的代码.
package cn.wz.traditional.wf; import javafx.scene.chart.PieChart; import java.util.HashMap; import java.util.Map; /** * Created by WangZhe on 2017/5/4. */ public class ThraedLocalTest { public static void main(String[] args) { new Thread(new Runnable() { public void run() { A a=new A(); a.sayHi(5); } }).start(); new Thread(new Runnable() { public void run() { A a=new A(); a.sayHello(); } }).start(); } static class A{ ThreadLocal<Integer> tl=new ThreadLocal<Integer>(); public void sayHi(Integer age){ tl.set(age); Integer data = tl.get(); data+=10; tl.set(data); System.out.println(tl.get()); } public void sayHello(){ tl.set(7); } } }
如上面代码所示ThreadLocal类在赋值和获取值时比我们之前写的代码方便了许多并不需要提供key值就能进行操作,其实ThreadLocal类的实现和我们之前的实现差不多的差不多,下面介绍下threadLocal类的方法实现,
ThreadLocal 类方法详解
ThreadLocal类提供了一下四种方法供程序员调用,下面为大家介绍每个方法的实现。
InitialValue()方法,该方法在对象调用get方法时,之前并没有调用过set方法赋值的情况下调用该方法返回null值,如图所示,
set()方法,该方法是为线程范围变量的赋值方法,其内容如下:
GetMap()方法内容
CreateMap方法内容
get方法:给方法是获取线程范围变量的方法,我们已经知道了线程范围变量保存在一个以ThreadLocal实例为key值得map集合中所以对此这里不再进行赘述了,我们着重关注一下调用get之前并没有使用set方法为集合中该项赋值的情况,
如下所示:
remove方法:该方法是移除当前线程中该ThreadLocal实例对应的线程范围变量值,注意,并不是当前线程的所有范围变量值,如图所示
总结:
java API提供ThreadLocal类来保存线程范围变量,一个ThreadLocal对象在一个线程上只能绑定一个线程范围变量,但一个ThreadLocal对象可以为多个不同的线程绑定线程范围变量值。