本节主要在于Java线程之间的通信,主要涉及的是volatile关键字的用法。
首先,先提出此问题产生背景,如果有两个线程t1,t2,t1作为一个我们正常的事务处理逻辑,就是创建一个list,然后在其中添加元素,把t2线程当作t1的监控,当t1中的list添加5个的时候,通知t2,执行t2 的逻辑,怎么做?
为了说明这个问题,先看下面一个代码:
public class ListAdd1 {
private static List<String> list = new ArrayList<String>();
public void add(){
list.add("zhangsan");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd1 list1 = new ListAdd1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
list1.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (list.size() == 5) {
System.out.println("当前线程:" + Thread.currentThread().getName() + "list.size() == 5 线程停止");
throw new RuntimeException();
}
}
}
} ,"t2");
t1.start();
t2.start();
}
}
但是我们来看执行结果:
t1执行了10次,此后t2一致处于等待状态......
可能有人会想到先将t2运行起来进行监控,然后执行t1,那样就能监控到,感兴趣的可以试验下,结果仍旧是这样。
造成这个情况的原因就是,list作为类的一个属性,在线程运行的时候,会将其创建一个副本存储空间,存在于自己的线程空间中中,等自己这个线程运行完毕之后,才将其释放,也就是说:
先运行t1,后运行t2的时候,t2中的list的size一直就是1,这是因为运行t2的时候,t1已经运行了一次,因此list的size就是1。
先运行t2,后运行t1的时候,t2中的list的size一直就是0,这是因为运行t2的时候,t1已经没有运行,因此list的size就是0。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
根据以上结果,显然,没有达到应有的需求,因此我们就引入一个关键字:volatile。
volatile是Java提供的一个轻量级的同步机制,在并发编程中,volatile关键字修饰的资源可以在线程中作为公共资源进行访问。
对上面的代码改进一行,就是:
private volatile static List<String> list = new ArrayList<String>();
这样再次运行:
取得想要的效果。