标签:
EvenGenerator 是一个偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果。在本案例中,充当被共享的资源。
EvenChecker 实现了 Runnable 接口,可以启动新的线程执行 run() 任务,用于检测所指向的偶数生成器是否每次都返回偶数值。
EvenCheckerThreadDemo 用于演示多线程下的执行情况。
EvenGenerator, 偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果。
这里的 next() 方法并非线性安全,在多线程同时访问时,可能会返回奇数。一个线程执行了第一个累加语句后,被调度器中断,替换上下文,另一个进程开始执行 next() 方法,则会返回奇数。
public class EvenGenerator { private int count = 0; public int next(){ count++; count++; return count; } }
EvenChecker 检测指向的 EvenGenerator 是不是每次都返回偶数。
public class EvenChecker implements Runnable { private EvenGenerator eg; private final int id = count++; private static int count = 0; @Override public void run() { while (true){ int res = eg.next(); if (res % 2 != 0){ System.out.println("not even" + res + " | Thread # " + id); break; } } } public EvenChecker(EvenGenerator eg){ this.eg = eg; } }
演示多线程下的执行情况,多个线程同时执行 EvenChecker ,但是引用的是同一个 EvenGenerator
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class EvenCheckerThreadDemo { public static void main(){ ExecutorService exec = Executors.newCachedThreadPool(); EvenGenerator eg = new EvenGenerator(); for (int i = 0; i< 5 ; i++){ exec.execute(new EvenChecker(eg)); } } }
使用 synchronized 关键词,使得 next() 方法线程安全,确保同一时间内,最多只有一个线程进入该方法。
public class EvenGenerator { private int count = 0; public synchronized int next(){ count++; count++; return count; } }
使用 Lock 把访问、修改共享变量的语句进行同步,确保同一时间内,最多只有一个线程进入该块代码。使用 try-finally 结构,可以确保 Lock 一定被释放。
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class EvenGenerator { private int count = 0; private Lock lock = new ReentrantLock(); public int next(){ lock.lock(); try { count++; count++; return count; } finally{ lock.unlock(); } } }
参考资料
Page 827, Resolving shared resource contention, Thinking in Java
[Java Concurrent] 并发访问共享资源的简单案例
标签:
原文地址:http://www.cnblogs.com/TonyYPZhang/p/5551637.html