java提供关键字 syncchronized ,为防止资源冲突提供了内置支持。当任务要执行被 syncchronized 关键字保护的代码片段的时候,他将会检查锁是否可用,然后获取锁,执行代码,释放锁。
在使用并发时,将域设置为private 是非常重要的,否则 syncchronized 关键字将不能防止其他任务直接访问域,这样就会产生冲突。
你应该什么时候同步呢?可以运用 Brian 的同步规则:
如果你正在写一个变量,他可能接下来将被另一个线程读取,或者正在读取一个上次已经被另一个线程写过的变量,那么你必须使用同步,并且,读写线程必须用相同的监视器锁同步!
/**
*
*/
package com.cxm.thread.sync;
/**
* @author admin
*
*/
public abstract class IntGenerator
{
private volatile boolean canceled = false;
public abstract int next();
public void cancel(){
canceled = true;
}
public boolean isCanceled(){
return canceled;
}
}
/**
*
*/
package com.cxm.thread.sync;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author admin
*
*/
public class EvenChecker implements Runnable
{
private IntGenerator generator;
private final int id;
public EvenChecker(IntGenerator g ,int ident){
this.generator = g;
this.id = ident;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
while(!generator.isCanceled()){
int val = generator.next();
if(val%2 != 0){
System.out.println(val + " not even!");
generator.cancel();
}
}
}
public static void test(IntGenerator g ,int count){
System.out.println("Press Control-C to exit");
ExecutorService exec = Executors.newCachedThreadPool();
for(int i =0;i<count;i++){
exec.execute(new EvenChecker(g, i));
}
exec.shutdown();
}
public static void test(IntGenerator g){
test(g,10);
}
}
/**
*
*/
package com.cxm.thread.sync;
/**
* @author admin
*
*/
public class EvenGenerator extends IntGenerator
{
private int currentEvenValue = 0;
/* (non-Javadoc)
* @see com.cxm.thread.syns.IntGenerator#next()
*/
@Override
public int next()
{
++currentEvenValue;
Thread.yield();
++currentEvenValue;
return currentEvenValue;
}
public static void main(String[] args)
{
EvenChecker.test(new EvenGenerator());
}
}
同步控制:
/**
*
*/
package com.cxm.thread.sync;
/**
* @author admin
*
*/
public class EvenGenerator extends IntGenerator
{
private int currentEvenValue = 0;
/* (non-Javadoc)
* @see com.cxm.thread.syns.IntGenerator#next()
*/
@Override
public synchronized int next()
{
++currentEvenValue;
Thread.yield();
++currentEvenValue;
return currentEvenValue;
}
public static void main(String[] args)
{
EvenChecker.test(new EvenGenerator());
}
}
使用显式的Lock对象
/**
*
*/
package com.cxm.thread.sync.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.cxm.thread.sync.EvenChecker;
import com.cxm.thread.sync.IntGenerator;
/**
* @author admin
*
*/
public class MutexEvenGenerator extends IntGenerator
{
private int currentEvenValue = 0;
private Lock lock = new ReentrantLock();
/* (non-Javadoc)
* @see com.cxm.thread.sync.IntGenerator#next()
*/
@Override
public int next()
{
lock.lock();
try{
++currentEvenValue;
Thread.yield();
++currentEvenValue;
return currentEvenValue;
}finally{
lock.unlock();
}
}
public static void main(String[] args)
{
EvenChecker.test(new MutexEvenGenerator());
}
}
尽管try-finally所需要的代码比synchronized关键字多,但是这也代表了显式的Lock对象的优点之一。如果在使用synchronized 关键字时,某些事务失败了, 那么就会抛出一个异常,但是你没有机会去做任何的清理工作,使用了lock可以在finally中做清理工作。