IncreaseClient 中持有一个base,每次调用起increase方法后,返回原先的值,
increase方法自加两次,在check方法中判断返回值和最新值是否相差2.在多线程的环境下就会出错,因为++base不是原子性操作
package com.woxiaoe.study.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 自加类
* @author 小e
*
* 2010-4-24 下午08:39:19
*/
public class IncreaseClient {
private int base = 0;
public IncreaseClient() {
}
public int increase(){
int pre = base;
++ base;
Thread.currentThread().yield();
++ base;
return pre;
}
public boolean check(){
int pre = increase();
System.out.println("pre:" + pre + "\t" + "increase:" + base);
return pre - base == -2?true:false;
}
public static void main(String[] args) {
IncreaseClient ic = new IncreaseClient();
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++){
exec.execute(new IncreaseChecker(ic));
}
}
}
package com.woxiaoe.study.thread;
/**
* 验证多线程下自加的准确性
* @author 小e
*
* 2010-4-24 下午08:38:14
*/
public class IncreaseChecker extends Thread {
private IncreaseClient ic;
public IncreaseChecker(IncreaseClient ic) {
this.ic = ic;
}
@Override
public void run() {
while(ic.check()){
}
System.out.println(Thread.currentThread() + "自增出错");
System.exit(0);
}
}
解决资源共享的最简单方法极为给会产生冲突的方法加把锁,本例中只需将chenk()方法做如下修改
public synchronized boolean check(){
int pre = increase();
System.out.println("pre:" + pre + "\t" + "increase:" + base);
return increase() - base == -2?true:false;
}
另一种方法是显示的给代码加把锁:
public boolean check(){
lock.lock();
try{
int pre = increase();
System.out.println("pre:" + pre + "\t" + "increase:" + base);
return pre - base == -2?true:false;
}finally{
lock.unlock();
}
}
大体上当使用synchronized关键字时,需要写的代码量更少,并且用户出现的可能性也会降低,因此通常只在解决特殊问题时,才会显示的Lock对象。Lock对象提供了更细粒度的操作。