1

假设我有一个名为 Object 的类和一个名为 ObjectCreator 的线程,用于管理对象的创建。为简单起见,Object 具有属性:objectNumber 和 objectName。

如果我要创建一个名为 instance 的 Object 实例,它将由 ObjectCreator 持有。现在假设我需要另一个线程(我们称之为 ObjectChanger)来查看和操作实例;将实例变成静态对象有意义吗?

我已经设法通过将实例设为静态来查看结果,所以现在我可以执行以下操作:

ObjectCreator.instance.getName();

其中 getName() 是 Object 的一个方法。从我从类似问题的答案中读到的内容来看,静态事物是邪恶的,并且总是有解决方法。我读过的一个建议是将实例作为其构造函数的参数传递给 ObjectChanger,但是如果在我需要创建 ObjectChanger 时尚未创建实例怎么办?

也许这个问题更多的是关于 OOP 概念而不是多线程,或者它可能是重复的,所以请原谅我,但我在这里很迷茫。

编辑:为了解决弗兰基和吉姆的建议,这里有一些代码片段:

目的:

类对象

{
 private String objectName = "Something";
 private int objectNumber = 1;

 public synchronized void changeNumber(int newNumber)
 {
  objectNumber = newNumber;
 }
}

对象创建者:

class ObjectCreator extends Thread
{
 static Object instance;

 public ObjectCreator (Object something)
 {
  instance = something;
 }

 static void createObject()
 {
  ...
 }

 static Object getObject()
 {
  return instance;
 }
}

对象转换器:

public class ObjectChanger extends Thread
{
 private Object currentInstance = null;
 private int instanceNumber = null;

 public void run()
 {
  currentInstance = ObjectCreator.getObject(); //If I were to make getObject() non-static, this line churns up an error

  instanceNumber = currentInstance.getObjectNumber();
  currentInstance.changeNumber(2); //valid?
 }
}
4

5 回答 5

1

如果您希望一个线程能够访问未在其中创建的对象,则必须确保该线程具有它可以遵循的引用路径,从而导致新对象。

考虑以下代码,不涉及线程。

class MyObject { /* ... */ }

interface MyObjectProvider {
    MyObject getMyObject();
}

class Creator implements MyObjectProvider {
    private MyObject obj;
        /* ... */
    @Override
    public MyObject getMyObject() {
        return obj;
    }

    /** Invoked at some point in time. */
    void createMyObject() {
        obj = new MyObject();
    }
}

class Consumer {
    private MyObjectProvider provider;

    Consumer(MyObjectProvider mop) {
        provider = mop;
    }

    void consume() {
        // At some point in time...
        MyObject o = provider.getMyObject();
    }
}

程序示例:

public static void main(String[] args) {
    Creator creator = new Creator();
    Consumer consumer = new Consumer(creator);

    creator.createMyObject();
    consumer.consume();
}

当您将线程添加到混合中时,必须更改一些代码,但结构是相同的。正如您所指出的,这个想法是在一个线程中运行 Creator,而在另一个线程中运行 Consumer。所以,简而言之,这些是你应该研究的事情:

  • 并发控制:研究数据竞争synchronized互斥和它们的朋友。从这里开始
  • wait并且notify,如果消费者应该等待 MyObject 被创建。看这里

当您很好地掌握了这些概念时,您可以查看volatile关键字(注意它的陷阱),以及java.util.concurrent提供更好的并发原语、并发集合和原子变量的包。

于 2013-11-14T21:03:55.303 回答
0

为什么不能在 ObjectCreator 类中创建一个 getter 来检索所述对象?

例如:ObjectCreater.getMyObject()

编辑:

如果我没记错的话,我认为您正在寻找这样的东西:

public class ObjectCreator{
    ArrayList<Object> children;

    public ObjectCreator(){ 
         children = new ArrayList<Object>();
    }

    //returns back index in children array (for accessing from other threads)
    public int createObject( whatever params here ){
       Object o = new Object( params );
       children.add(o);
       return children.size()-1;
    }

}

由于我对您要解决的问题了解不多,因此我不确定它是否必须是线程安全的,是否要映射这些对象或以不同方式访问,但是我很困惑所有关于静态的混乱都在哪里...... .

于 2013-11-14T19:52:41.363 回答
0

您可以将对象放在列表结构中,例如Vector并将它们存储在ObjectCreator. 添加一个 getter 方法,ObjectCreator该方法将接受要接收的对象的索引。

于 2013-11-14T19:55:21.050 回答
0

这只是显示基本结构的骨架。错误处理留作练习:-)

public class MyObject { ... }
...
public class MyObjectCreator { 
    private Map<String,MyObject> createdObjects = new HashMap<>();
    public MyObject makeNewObject(int objNum, String objName)
    {
        MyObject o = new MyObject(objNum, objName);
        this.createdObjects.put(objName,o);
    }
    public MyObject getObject(String objName)
    {
        return this.createdObjects.get(objName);
    }
}
...
public class MyProgram {
    public static void main(String[] args)
    {
        MyObjectCreator oc = new MyObjectCreator();
        MyObject        mo = oc.makeNewObject(10,"aNewObject");
    ...

    MyObject o = oc.get("aNewObject");
    ...
于 2013-11-14T20:12:08.253 回答
0

如果您只想更改类字段的值,则应该将对象传递到新创建的线程中。那么就没有必要在持有者类中保留一个静态引用。

但正如已经评论的那样,我们需要更多信息来了解您想要对您的对象和线程做什么。

于 2013-11-14T20:12:15.077 回答