我正在使用执行程序框架来执行大型任务。我需要计算已完成的过程状态目的。所以我创建了一个带有计数器的单例类来保持计数。
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函数同步也会帮助我。如果没有那么我该怎么做才能使它正确。
答案 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();
}
}