8.2.3 实现同步
我们这里有一个简单的接口Increasable,该接口含有一个increase(int delta)方法,IncreaseImpl实现了这个接口,按照传递参数delta,以其大小从0开始增长,增长max次之后,判断结果是否还是delta的整数倍,即这句count%delta!=0,如果不是,则抛出IllegalStateException("Count state is illegal!")的异常。Increasable接口和实现IncreaseImpl类的代码如下所示。
顺序执行同一IncreaseImpl对象的方法,是不会有异常抛出的,但是让多个线程,以不同的delta参数并发增长,则很可能会抛出异常。我们为此撰写的测试代码如下所示。
1.我们使用Executors.newFixedThreadPool(2)生成一个可以包含两个线程的线程池;
2.然后提交两个FutureTask对象给线程池,即这句:pool.submit(new Runn able(){……});
3.接着等待这两个FutureTask对象执行完成;
4.FutureTask对象调用Increase对象的increase(int delta)方法。
由于两个线程使用同一个对象,如果increase(int delta)方法不是线程安全的,那么很容易抛出IllegalStateException异常。这样,我们在此测试方法里就会捕捉到ExecutionException异常,该异常的cause应该是increase(int delta)方法刚刚抛出来IllegalStateException异常;反之,如果increasable是线程安全的,则不会抛出ExecutionException异常。
非线程安全的测试方法如下。
IncreaseImpl对象是非线程安全的,那么最终必然会抛出异常消息为"Count state is illegal!"的异常。由于能否抛出异常与执行有很大关系,我们可以使用循环多运行几次,直至抛出异常。
现在,我们使用动态代理为IncreaseImpl对象创建一个运行时安全的代理对象,只要在调用increase(int delta)方法时为其加上这个对象作为同步锁,代码如下所示。
当调用目标对象的increase(int delta)方法时,我们添加了synchronized(delegate){……}同步代码块。
为了验证我们的想法,我们编写了方法testSynchronizedIncrease(),把线程安全的代理对象传递给increase(final Increasable increasable)方法,循环max次。测试代码大致如下所示。
启动线程安全的和非线程安全的测试,代码如下。
其实不管max值为多少,线程安全的和非线程安全的测试执行结果都一样,如下所示。