标签:
如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个线程写过的变量,那么你需要使用同步,并且,读写线程都必须用相同的监视器锁同步。--Brain同步规则
synchronized
可重入锁ReentrantLock
在java.util.concurrent.locks包中定义了显式的Lock,该Lock锁需要显式的创建、锁定和释放。比起synchronized关键字,显式的Lock锁使用起来更繁琐,在使用时也更有可能出错,但有更强大的功能。locks包中包含了两种锁ReentrantLock和ReentrantReadWriteLock。
public class LockTest { private int current = 0; private Lock lock = new ReentrantLock(); public int next(){ //lock.lock(); boolean flag = lock.tryLock(); if(flag){ try{ ++current; Thread.yield(); ++current; return current; }finally{ lock.unlock(); } }else{ System.out.println("locked"); return -1; } } }
显示锁可以去尝试获取锁,这是比synchronized关键字更为灵活的地方。tryLock(long timeout, TimeUnit unit)还可以设置你等待获取锁的时间。由于Lock锁更有可能出错,除非解决特殊问题,否则使用synchronized关键字即可。
volatile
使用volatile关键字可以使你定义的基本类型变量的赋值和返回操作为原子操作。
volatile可以是声明的字段具有可视性。可视性指只要你对字段进行了写操作,那么所有的读操作就都可以看到这个修改。因为线程对某一字段的修改,可能不会直接体现在内存中,其他线程也就获取不到最新的值。
volatile关键字应该慎重使用,需要进行线程同步时,首选还是synchronized关键字。
原子类
Java SE5提供了AtomicInteger、AtomicLong、AtomicReference等特殊的原子性变量类。这些类以boolean compareAndSet(int expect, int update)的形式进行原子性条件的更新。这些原子类都有基本的get、set操作,用来获取和设置值。
Atomic类的设计主要用来构建java.util.concurrent中的类,常规编程还是使用锁要更安全些,但是在涉及性能调优时,这些原子类就大有用武之地了。
public class AtomicityTest implements Runnable { public static void main(String[] args) { // TODO Auto-generated method stub new Timer().schedule(new TimerTask() { @Override public void run() { // TODO Auto-generated method stub System.err.println("aborting"); System.exit(0); } }, 5000); ExecutorService exec = Executors.newCachedThreadPool(); AtomicityTest at = new AtomicityTest(); exec.execute(at); while(true){ int val = at.getValue(); if(val % 2 != 0){ System.out.println(val); System.exit(0); } } } private AtomicInteger i = new AtomicInteger(0); public int getValue(){ return i.get(); } private void evenIncrement(){ i.addAndGet(2); System.out.println(i); } @Override public void run(){ while(true) evenIncrement(); } }
临界区和其他对象上同步
有时我们只希望某部分代码不被多个线程同时访问,这类被同步的代码块叫临界区。临界区可以使用synchronized关键字来建立。
synchronized(syncObject) { //临界区代码 }
某个线程在进入临界区代码块时,必须获得syncObject对象上的锁。需要注意的是,syncObject既可以是对象本身this,也可以使用其他的对象。在介绍synchronized关键字时说过,所有对象都含有一个锁,临界区就是通过对象锁来实现的。这样多个线程可以同时进入同一个对象,只要该对象被访问的代码块使用了不同的对象锁。
ThreadLocal
ThreadLocal通过根除对变量的共享来防止多线程中共享资源的冲突。ThreadLocal为使用相同的变量的每个不同的线程都创建不同存储。ThreadLocal对象通常当做静态字段来存储。下面的代码,相当于每一个线程都为其设置了一个Integer id。
public class ThreadLocalTest { public static ThreadLocal<Integer> value = new ThreadLocal<Integer>(){ protected synchronized Integer initialValue() { return 100; } }; public static void main(String[] args) { // TODO Auto-generated method stub new Timer().schedule(new TimerTask() { @Override public void run() { // TODO Auto-generated method stub System.exit(0); } }, 5000); ExecutorService exec = Executors.newCachedThreadPool(); for(int i=0; i<10; ++i){ exec.execute(new Accesor(value.get())); } exec.shutdown(); } } class Accesor implements Runnable { private int id; public Accesor(Integer id){ this.id = id.intValue(); System.out.println("init value: " + this.id); } public void run(){ while(true) id++; } }
标签:
原文地址:http://www.cnblogs.com/pzhblog/p/4573857.html