Java Concurrent Programming (5)

5 原子变量
  java.util.concurrent.atomic包中添加原子变量类。所有原子变量都公开"比较并设置"原语,这些原语都是使用平台上可用的最快本机结构来实现的。原子变量类可以认为是volatile变量的泛化,它扩展了volatile变量的概念,来支持原子条件的比较并设置更新。读取和写入原子变量与读取和写入对volatile变量的访问具有相同的存取语义。concurrent.atomic包中原子变量类共12个,分成4组:计量器,域更新器,数组以及符合变量。最常用的原子变量是计量器:AtomicInteger,AtomicLong,AtomicBoolean以及AtomicReference。这四个class都提供两个constructor, 默认无参和指定参数。默认的constructor的值为零,false或null,依据数据类型初始化对象。他们的set与get方法以atomic的设定与取得值。getAndSet方法能够在返回初始值的时候atomic化的设定变量成新的值。addAndGet与getAndAdd方法提供“前置”与“后”的运算符给指定值的加法运算,这两个method让程序能够对变量增或减一个指定值,包括负值。incrementAndGet,decrementAndGet,getAndIncrement,getAndDecrement方法,提供了前置递增,前置递减,后递增,后递减的功能。compareAndSet和weakCompareAndSet方法,提供了有条件修改程序的方法。这两个method有两个参数,在method启动时预期数据所具有的值,以及要把数据所设定成的值。method只会在变量具有预期值的时候才会将它设置成新值。如果当前值不等于预期值,该变量不会被重新赋值,其method返回false。如果当前值等于预期值会返回true,并且此时值会被设定成新值。这个method的week形式基本也是一样的,区别在于,week形式少了一项保证:如果method放回的是false,该变量不会被变动,但是这并不代表现有值不是预期值。这个method不管初始值是否为预期值都可能会无法更新该值。此外,AtomicInteger和AtomicLong还支持从Integer到int,float,double的转化输出。
  以下是使用的一个小例子:
public class ActomicIntegerDemo {
	//
	private final AtomicInteger counter = new AtomicInteger();
	
	public int getCounter(){
		return counter.get();
	}
	
	public int increment(){
		return counter.incrementAndGet();
	}
	
	public int decrement(){
		return counter.decrementAndGet();
	}
	
	public static void main(String[] args) throws Exception {
		
		final ActomicIntegerDemo atd = new ActomicIntegerDemo();
		
		new Thread(){
			public void run(){
				for(int i = 0; i < 100; i ++){
					atd.increment();
				}
				
			}
		}.start();
		
		new Thread(){
			public void run(){
				for(int i = 0; i < 100; i ++){
					atd.decrement();
				}
			}
		}.start();
		
		Thread.sleep(2 * 1000);
		System.out.println("result = " + atd.getCounter());
	}
}

5.1 线程池
  Executor为所有线程池的父接口。
  ExecutorService接口继承自Executor接口,增加了一些池的管理功能,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。其实现类为AbstractExecutorService,其实现了submit和doInvokeAny重载版本的方法,AbstractExecutorService为一个抽象类,而我们经常用到的ThreadPoolExecutor就是继承自AbstractExecutorService,ThreadPoolExecutor实现了其他所有AbstractExecutorService未实现的方法。
  ScheduledExecutorService接口继承自ExecutorService,增加了一些可安排在给定的延迟后运行或定期执行命令的方法。其实现类为ScheduledThreadPoolExecutor,ScheduledThreadPoolExecutor继承自ThreadPoolExecutor并实现了ScheduledExecutorService,它可另行安排在给定的延迟后运行命令,或者定期执行命令,ScheduledThreadPoolExecutor中含有了所有的方法。
  Executors为一个工厂类,提供了很多的方法,包括创建ExecutorService,ScheduledExecutorService,ThreadFactory,Callable。
  Callable接口类似与Runnable接口,有相同的功能,只不过Callable提供的call方法有返回值,而Runnable的run方法无返回值。

5.2 ThreadLocal变量
  ThreadLocal是Thread的局部变量,其为每个使用该变量的线程提供独立的变量副本。所以每一个线程都可以独立的改变自己的副本,而不会影响其他线程所对应的副本。从线程的角度看,目标变量就是线程的本地变量,这也是类名中"Local"所要表达的意思。
  ThreadLocal被定义为:
public class ThreadLocal<T>{}

  T为线程局部变量的类型。该类定义了4个方法:
protected T initialValue():返回此线程局部变量的当前线程的“初始值”。线程第一次使用get()方法访问变量时将调用次方法,但如果线程之前调用了set方法,则不会对该线程在调用initialValue方法。通常,此方法对每个线程最多调用一次,但如果在调用get后又调用了remove方法,则可能再次调用此方法。该方法返回null,需要我们覆写这个方法。一般使用匿名内部类完成此操作。
public T get():返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用initialValue方法返回的值。
public void set(T value):将此线程局部变量的当前线程副本中的值设置为制定值。
public void remove():移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其initialValue方法重新初始化其值。
  以下是一个小例子,每个线程都产生了独立的顺序号,互补干扰:
public class SequenceNum {
	
	private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
		public Integer initialValue(){
			return 0;
		}
	};
	
	public int nextNum(){
		seqNum.set(seqNum.get() + 1);
		return seqNum.get();
	}
	
	private static class Task implements Runnable{
		//
		private final SequenceNum seq; 
		
		public Task(SequenceNum seq ){
			this.seq = seq;
		}
		
		public void run(){
			try {
				for(int i = 0; i < 3; i ++){
					System.out.println("current thread " + Thread.currentThread().getId() + " , seq num = " + seq.nextNum());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		
		final SequenceNum seq = new SequenceNum();
		
		new Thread(new Task(seq)).start();
		
		new Thread(new Task(seq)).start();
		
		new Thread(new Task(seq)).start();
		
	}
}

猜你喜欢

转载自technoboy.iteye.com/blog/1041805