4、AtomicInteger
对变量的读写操作都是原子操作(除了long或者double的变量),但像数值类型的++ --操作不是原子操作,像i++中包含了获得i的原始值、加1、写回i、返回原始值,在进行类似i++这样的操作时如果不进行同步问题就大了。好在java.util.concurrent.atomic为我们提供了很多工具类,可以以原子方式更新变量。
以AtomicInteger为例,提供了代替++ --的getAndIncrement()、incrementAndGet()、getAndDecrement()和decrementAndGet()方法,还有加减给定值的方法、当前值等于预期值时更新的compareAndSet()方法。
下面的例子中用AtomicInteger保存全局验证次数(第69行做了自增的操作),因为validateNode()方法会同时被多个线程调用,所以直接用int不同步是不行的,但用AtomicInteger在这种场合下就很合适。
- package service.mock;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.logging.Logger;
- import service.Node;
- /**
- * 模拟执行节点验证的Mock类
- *
- * @author DigitalSonic
- */
- public class MockNodeValidator {
- public static final List<Node> ENTRIES = new ArrayList<Node>();
- private static final Map<String, Node> NODE_MAP = new HashMap<String, Node>();
- private static AtomicInteger count = new AtomicInteger(0);
- private static Logger logger = Logger.getLogger("MockNodeValidator");
- /*
- * 构造模拟数据
- */
- static {
- Node node0 = new Node("NODE0", "http://node0/check?wsdl"); //入口0
- Node node1 = new Node("NODE1", "http://node1/check?wsdl");
- Node node2 = new Node("NODE2", "http://node2/check?wsdl");
- Node node3 = new Node("NODE3", "http://node3/check?wsdl");
- Node node4 = new Node("NODE4", "http://node4/check?wsdl");
- Node node5 = new Node("NODE5", "http://node5/check?wsdl");
- Node node6 = new Node("NODE6", "http://node6/check?wsdl"); //入口1
- Node node7 = new Node("NODE7", "http://node7/check?wsdl");
- Node node8 = new Node("NODE8", "http://node8/check?wsdl");
- Node node9 = new Node("NODE9", "http://node9/check?wsdl");
- node0.setDependencies(new String[] { node1.getWsdl(), node2.getWsdl() });
- node1.setDependencies(new String[] { node3.getWsdl(), node4.getWsdl() });
- node2.setDependencies(new String[] { node5.getWsdl() });
- node6.setDependencies(new String[] { node7.getWsdl(), node8.getWsdl() });
- node7.setDependencies(new String[] { node5.getWsdl(), node9.getWsdl() });
- node8.setDependencies(new String[] { node3.getWsdl(), node4.getWsdl() });
- node2.setResult("FAILED");
- NODE_MAP.put(node0.getWsdl(), node0);
- NODE_MAP.put(node1.getWsdl(), node1);
- NODE_MAP.put(node2.getWsdl(), node2);
- NODE_MAP.put(node3.getWsdl(), node3);
- NODE_MAP.put(node4.getWsdl(), node4);
- NODE_MAP.put(node5.getWsdl(), node5);
- NODE_MAP.put(node6.getWsdl(), node6);
- NODE_MAP.put(node7.getWsdl(), node7);
- NODE_MAP.put(node8.getWsdl(), node8);
- NODE_MAP.put(node9.getWsdl(), node9);
- ENTRIES.add(node0);
- ENTRIES.add(node6);
- }
- /**
- * 模拟执行远程验证返回节点,每次调用等待500ms
- */
- public static Node validateNode(String wsdl) {
- Node node = cloneNode(NODE_MAP.get(wsdl));
- logger.info("验证节点" + node.getName() + "[" + node.getWsdl() + "]");
- count.getAndIncrement();
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return node;
- }
- /**
- * 获得计数器的值
- */
- public static int getCount() {
- return count.intValue();
- }
- /**
- * 克隆一个新的Node对象(未执行深度克隆)
- */
- public static Node cloneNode(Node originalNode) {
- Node newNode = new Node();
- newNode.setName(originalNode.getName());
- newNode.setWsdl(originalNode.getWsdl());
- newNode.setResult(originalNode.getResult());
- newNode.setDependencies(originalNode.getDependencies());
- return newNode;
- }
- }
package service.mock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import service.Node;
/**
* 模拟执行节点验证的Mock类
*
* @author DigitalSonic
*/
public class MockNodeValidator {
public static final List<Node> ENTRIES = new ArrayList<Node>();
private static final Map<String, Node> NODE_MAP = new HashMap<String, Node>();
private static AtomicInteger count = new AtomicInteger(0);
private static Logger logger = Logger.getLogger("MockNodeValidator");
/*
* 构造模拟数据
*/
static {
Node node0 = new Node("NODE0", "http://node0/check?wsdl"); //入口0
Node node1 = new Node("NODE1", "http://node1/check?wsdl");
Node node2 = new Node("NODE2", "http://node2/check?wsdl");
Node node3 = new Node("NODE3", "http://node3/check?wsdl");
Node node4 = new Node("NODE4", "http://node4/check?wsdl");
Node node5 = new Node("NODE5", "http://node5/check?wsdl");
Node node6 = new Node("NODE6", "http://node6/check?wsdl"); //入口1
Node node7 = new Node("NODE7", "http://node7/check?wsdl");
Node node8 = new Node("NODE8", "http://node8/check?wsdl");
Node node9 = new Node("NODE9", "http://node9/check?wsdl");
node0.setDependencies(new String[] { node1.getWsdl(), node2.getWsdl() });
node1.setDependencies(new String[] { node3.getWsdl(), node4.getWsdl() });
node2.setDependencies(new String[] { node5.getWsdl() });
node6.setDependencies(new String[] { node7.getWsdl(), node8.getWsdl() });
node7.setDependencies(new String[] { node5.getWsdl(), node9.getWsdl() });
node8.setDependencies(new String[] { node3.getWsdl(), node4.getWsdl() });
node2.setResult("FAILED");
NODE_MAP.put(node0.getWsdl(), node0);
NODE_MAP.put(node1.getWsdl(), node1);
NODE_MAP.put(node2.getWsdl(), node2);
NODE_MAP.put(node3.getWsdl(), node3);
NODE_MAP.put(node4.getWsdl(), node4);
NODE_MAP.put(node5.getWsdl(), node5);
NODE_MAP.put(node6.getWsdl(), node6);
NODE_MAP.put(node7.getWsdl(), node7);
NODE_MAP.put(node8.getWsdl(), node8);
NODE_MAP.put(node9.getWsdl(), node9);
ENTRIES.add(node0);
ENTRIES.add(node6);
}
/**
* 模拟执行远程验证返回节点,每次调用等待500ms
*/
public static Node validateNode(String wsdl) {
Node node = cloneNode(NODE_MAP.get(wsdl));
logger.info("验证节点" + node.getName() + "[" + node.getWsdl() + "]");
count.getAndIncrement();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return node;
}
/**
* 获得计数器的值
*/
public static int getCount() {
return count.intValue();
}
/**
* 克隆一个新的Node对象(未执行深度克隆)
*/
public static Node cloneNode(Node originalNode) {
Node newNode = new Node();
newNode.setName(originalNode.getName());
newNode.setWsdl(originalNode.getWsdl());
newNode.setResult(originalNode.getResult());
newNode.setDependencies(originalNode.getDependencies());
return newNode;
}
}
上述代码还有另一个功能,就是构造测试用的节点数据,一共10个节点,有2个入口点,通过这两个点能够遍历整个系统。每次调用会模拟远程访问,等待500ms。环境间节点依赖如下:
Node1 [Node3, Node4]
Node2 [Node5]
Node6 [Node7, Node8]
Node7 [Node5, Node9]
Node8 [Node3, Node4]
5、CountDownLatch
CountDownLatch是一个一次性的同步辅助工具,允许一个或多个线程一直等待,直到计数器值变为0。它有一个构造方法,设定计数器初始值,即在await()结束等待前需要调用多少次countDown()方法。CountDownLatch的计数器不能重置,所以说它是“一次性”的,如果需要重置计数器,可以使用CyclicBarrier。在运行环境检查的主类中,使用了CountDownLatch来等待所有验证结束,在各个并发验证的线程完成任务结束前都会调用countDown(),因为有3个并发的验证,所以将计数器设置为3。
最后将所有这些类整合起来,运行环境检查的主类如下。它会创建线程池服务和验证服务,先做一次验证(相当于是对系统做次初始化),随后并发3个验证请求。系统运行完毕会显示实际执行的节点验证次数和执行时间。如果是顺序执行,验证次数应该是13*4=52,但实际的验证次数会少于这个数字(我这里最近一次执行了33次验证),因为如果同时有两个线程要验证同一节点时只会做一次验证。关于时间,如果是顺序执行,52次验证每次等待500ms,那么验证所耗费的时间应该是26000ms,使用了多线程后的实际耗时远小于该数字(最近一次执行耗时4031ms)。
- package service.mock;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.CountDownLatch;
- import service.Node;
- import service.ThreadPoolService;
- import service.ValidationService;
- /**
- * 模拟执行这个环境的验证
- *
- * @author DigitalSonic
- */
- public class ValidationStarter implements Runnable {
- private List<String> entries;
- private ValidationService validationService;
- private CountDownLatch signal;
- public ValidationStarter(List<String> entries, ValidationService validationService,
- CountDownLatch signal) {
- this.entries = entries;
- this.validationService = validationService;
- this.signal = signal;
- }
- /**
- * 线程池大小为10,初始化执行一次,随后并发三个验证
- */
- public static void main(String[] args) {
- ThreadPoolService threadPoolService = new ThreadPoolService(10);
- ValidationService validationService = new ValidationService(threadPoolService);
- List<String> entries = new ArrayList<String>();
- CountDownLatch signal = new CountDownLatch(3);
- long start;
- long stop;
- for (Node node : MockNodeValidator.ENTRIES) {
- entries.add(node.getWsdl());
- }
- start = System.currentTimeMillis();
- validationService.validate(entries);
- threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
- threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
- threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
- try {
- signal.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- stop = System.currentTimeMillis();
- threadPoolService.destoryExecutorService(1000);
- System.out.println("实际执行验证次数: " + MockNodeValidator.getCount());
- System.out.println("实际执行时间: " + (stop - start) + "ms");
- }
- @Override
- public void run() {
- validationService.validate(entries);
- signal.countDown();
- }
- }
package service.mock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import service.Node;
import service.ThreadPoolService;
import service.ValidationService;
/**
* 模拟执行这个环境的验证
*
* @author DigitalSonic
*/
public class ValidationStarter implements Runnable {
private List<String> entries;
private ValidationService validationService;
private CountDownLatch signal;
public ValidationStarter(List<String> entries, ValidationService validationService,
CountDownLatch signal) {
this.entries = entries;
this.validationService = validationService;
this.signal = signal;
}
/**
* 线程池大小为10,初始化执行一次,随后并发三个验证
*/
public static void main(String[] args) {
ThreadPoolService threadPoolService = new ThreadPoolService(10);
ValidationService validationService = new ValidationService(threadPoolService);
List<String> entries = new ArrayList<String>();
CountDownLatch signal = new CountDownLatch(3);
long start;
long stop;
for (Node node : MockNodeValidator.ENTRIES) {
entries.add(node.getWsdl());
}
start = System.currentTimeMillis();
validationService.validate(entries);
threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
threadPoolService.execute(new ValidationStarter(entries, validationService, signal));
try {
signal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
stop = System.currentTimeMillis();
threadPoolService.destoryExecutorService(1000);
System.out.println("实际执行验证次数: " + MockNodeValidator.getCount());
System.out.println("实际执行时间: " + (stop - start) + "ms");
}
@Override
public void run() {
validationService.validate(entries);
signal.countDown();
}
}
=================================我是分割线==============================
本文没有覆盖java.util.concurrent中的所有内容,只是挑选一些比较常用的东西,想要获得更多详细信息请阅读JavaDoc。自打有了“轮子”理论,重复造大轮子的情况的确少了,但还是有人会做些小轮子,例如编写多线程程序时用到的小工具(线程池、锁等等),如果可以,请让自己再“懒惰”一点吧~