同步计数器计数不正确

时间:2012-11-19 04:24:38

标签: java synchronization counter

对于每个对象的创建,我希望它可以通过标识符唯一地访问。我正在使用递增的静态值来跟踪已创建的对象数,并且每次构造一个新对象时,我使其标识符等于count + 1(并递增计数)。我遇到的问题是同步不起作用。以下是代码的简化版本:

public static final Hashtable MODULES = new Hashtable();
private static final Object countLock = new Object();
private static int count = 0;
private final String identifier;
private final String name;

public Class(String name) {
    this.identifier = String.valueOf(incrementCount());
    this.name = name;
    MODULES.put(identifier, name);
}

private static int incrementCount() {
     synchronized (countLock) {
        return ++count;
    }
}

现在当我用这个测试时(不可否认,但不可否认,但确定它有效):

    for (int x = 0; x < 100; x++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Class m = new Class("Name");
            }
        }).start();
    }
    System.out.println(Module.MODULES.size());

我的输出从60分到100分。显然我不希望那种不可靠性。一个动荡的领域会在这里运作吗(我尝试过相同的结果)我不确定如何确保每个class对象都有不同的标识符。欢迎任何解决方案。

注意:出于特定的实现原因,我无法访问java.util.concurrent。

4 个答案:

答案 0 :(得分:3)

你的锁工作正常,但问题是不同的。您正在通过新的Thread初始化每个对象。 当线程在后台运行时,主线程会立即打印计数。在两者之间设置适当的延迟,您将看到正确的计数。

public static void main(String[] args) throws InterruptedException{
    for (int x = 0; x < 100; x++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter m = new Counter("Name");
            }
        }).start();
    }
    Thread.sleep(1000);//put a delay
    System.out.println(MODULES.size());
}

答案 1 :(得分:1)

试试这个:

 for (int x = 0; x < 100; x++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Class m = new Class("Name");
            }
        }).start();
    }

    Thread.sleep(500);

    System.out.println(Module.MODULES.size());

答案 2 :(得分:0)

您正在打印未同步的哈希表的大小。 在语句MODULES.put(identifier,name);

之前添加一个synchronized语句
synchronized (MODULES) {
        MODULES.put(identifier, name);
    }

它对我有用。

答案 3 :(得分:0)

以下是我在代码中看到的问题:语句Class m = new Class("Name");位于run()函数中,而不是Runnable实现<的构造函数中/ em>在您的代码中。

如果我必须编写类似的代码,我会这样写:

public class ModuleTest {

    public static void main(String[] args) {
    for (int x = 0; x < 100; x++) {
        new Thread(new Runnable() {
            {
                Module m = new Module("Name");
            }
            @Override
            public void run() {
                // do something
            }
        }).start();
    }
    System.out.println(Module.MODULES.size());
    }
}

查看上面的语句Module m = new Module("Name");的位置。它不在run()函数中,因为调用run()时会调用start()。该声明位于未命名的大括号{}之间,在您的代码中构建Runnable的匿名实现时调用该大括号。{/ p>

要完成上面的代码,这里是Module类:

import java.util.Hashtable;

public class Module {

    public static final Hashtable MODULES = new Hashtable();
    private static final Object countLock = new Object();
    private static int count = 0;
    private final String identifier;
    private final String name;

    public Module(String name) {
        this.identifier = String.valueOf(incrementCount());
        this.name = name;
        MODULES.put(identifier, name);
    }

    private synchronized static int incrementCount() {
            return ++count;
    }
}