同步执行程序框架中的资源

时间:2015-03-23 19:28:24

标签: java multithreading executorservice

我正在使用执行程序框架来执行大型任务。我需要计算已完成的过程状态目的。所以我创建了一个带有计数器的单例类来保持计数。

public class ProgramInitializationTracker {

    private static Map<String, Integer> programInitializedTracker = new HashMap<>();
    private static ProgramInitializationTracker instance;

    private ProgramInitializationTracker(){

    }

    public static ProgramInitializationTracker getInstance(){
        if(instance == null){
            synchronized (ProgramInitializationTracker.class) {
                if(instance == null){
                    instance = new ProgramInitializationTracker();
                }
            }
        }
        return instance;
    }
    public Integer getProgramInitializedTracker(String key) {
        return programInitializedTracker.get(key);
    }

    public void setProgramInitializedTracker(String key, int value) {
        synchronized (ProgramInitializationTracker.class) {
            ProgramInitializationTracker.programInitializedTracker.put(key, value);
        }
    }
}

但问题是只有同步set方法才能真正确保我有正确的count值。至于我可以获得多线程。让get函数同步也会帮助我。如果没有那么我该怎么做才能使它正确。

2 个答案:

答案 0 :(得分:1)

当Java已经为您提供此功能时,您不应尝试实现对集合的自己的线程安全访问。

您应该使用ConcurrentHashMap。诸如get之类的读取不会阻止。

但是,不应使用Integer类型作为存储在映射中的值,而应使用AtomicInteger,这将确保尝试修改与同一键关联的值的多个线程将是线程安全的。< / p>

答案 1 :(得分:0)

在您发布的限制条件下,只需在您提交给AtomicInteger的任务和您希望拥有指标的地点之间共享ExecutorService的实例即可。 variant1用于包含所有任务的单个计数器,variant2用于具有每个任务类型的计数器。这段代码(应该)是线程安全的。

@ThreadSafe
class Test {

    private static class CountingRunnable implements Runnable {
        @Nonnull
        private final Runnable actualTask;

        @Nonnull
        private final AtomicInteger submitted;

        public CountingRunnable(@Nonnull Runnable actualTask, @Nonnull AtomicInteger submitted) {
            this.actualTask = actualTask;
            this.submitted = submitted;
        }

        @Override
        public void run() {
            actualTask.run();
            submitted.incrementAndGet();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        variant2();
    }

    private static void variant1() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(2);

        AtomicInteger counter = new AtomicInteger();

        final CountDownLatch latch = new CountDownLatch(1);

        service.submit(new CountingRunnable(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    latch.countDown();
                } catch (InterruptedException e) {}
            }
        }, counter));

        latch.await();
        System.out.println(counter.get());
        service.shutdown();
    }

    private enum TaskType {
        TYPE_1,
        TYPE_2
    }

    private static void variant2() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(2);

        final CountDownLatch latch = new CountDownLatch(2);
        final EnumMap<TaskType, AtomicInteger> metrics = new EnumMap<>(TaskType.class);
        metrics.put(TaskType.TYPE_1, new AtomicInteger());
        metrics.put(TaskType.TYPE_2, new AtomicInteger());

        service.submit(new CountingRunnable(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, metrics.get(TaskType.TYPE_1)));

        service.submit(new CountingRunnable(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, metrics.get(TaskType.TYPE_2)));

        latch.await();

        System.out.println("type 1: " + metrics.get(TaskType.TYPE_1));
        System.out.println("type 2: " + metrics.get(TaskType.TYPE_2));

        service.shutdown();
    }
}