2

对于对象的每次创建,我希望它可以由标识符唯一地访问。我使用递增的静态值来跟踪已创建的对象数量,并且每次构造新对象时,我都会使其标识符等于 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

4 回答 4

3

您的锁工作正常,但问题有所不同。您正在通过 new 初始化每个对象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());
}
于 2012-11-19T04:41:17.690 回答
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());
于 2012-11-19T04:38:38.630 回答
0

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

synchronized (MODULES) {
        MODULES.put(identifier, name);
    }

这个对我有用。

于 2012-11-19T04:41:18.280 回答
0

这是我在您的代码中看到的问题:该语句Class m = new Class("Name");run()函数中,而不是在您的代码中实现Runnable的构造函数中。

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

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

并完成上面的代码,这里是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;
    }
}
于 2012-11-19T10:43:54.250 回答