11

我有一个启动 2 个单独线程的 Java 类。第一个线程启动良好,所有变量都是正确的。

当我启动第二个线程时,线程一的全局变量更改为线程 2 中设置的值。

我尝试在更新全局变量的地方添加同步块,但这不起作用。

有没有办法解决这个问题?我希望每个线程都启动并使用自己的值,而不会干扰其他线程值。

编辑:

我的 Thread 类的片段:

  public abstract class ConsumerIF implements Runnable {

      public static Element root = null;
      public static String name = null;
      public static String type = null;
      public static String location = null;

      public final synchronized void reconfigure() throws FatalDistributionException {


            Document doc = builder.build(new StringReader(xmlCollector));
            root = doc.getRootElement();
            Element nameElement = root.getChild("name");
            Element typeElement = root.getChild("type");
            Element locationElement = root.getChild("location");
            Element scheduleElement = root.getChild("schedule");

            if (nameElement != null && typeElement != null && locationElement != null){
                name = nameElement.getTextTrim();
                type = typeElement.getTextTrim();
                location = locationElement.getTextTrim();
            }

      }
  }
4

5 回答 5

16

静态变量在所有线程之间共享,这就是使它们成为静态的原因。如果要使用不同的值,请使用 ThreadLocals 或(更好),在不同线程中使用具有非静态变量的不同对象。如果没有进一步的代码,很难说更多。

于 2013-05-29T08:20:52.660 回答
6

同步仅控制线程对共享状态的访问。

如果您想要每个线程单独的状态,那么您需要为每个线程声明该信息的不同实例(例如类)。Thread例如,只需在 each的方法中实例化一个新对象run(),或执行相关结构的副本(例如,集合的深层副本)

另一种方法是调查ThreadLocal,其中每个 Thread 将具有指定资源的不同副本。

于 2013-05-29T08:18:14.470 回答
2

如果您不想共享变量,则不要使用全局变量(您可能是指static在 Java 中)。使用线程启动时初始化的新对象创建一个新字段。例子:

public class HelloThread extends Thread {
    private MyObject myThreadVariable; // This is the thread-local variable

    public void run() {
        myThreadVariable = new MyObject(); // initialization when the thread starts
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new HelloThread()).start(); 
        (new HelloThread()).start();
    }
}

如果您确实需要跨不同代码段在本地访问您的对象到您的线程,请使用ThreadLocal

public class UniqueThreadIdGenerator {
      private static final AtomicInteger uniqueId = new AtomicInteger(0);

      // Value obtained from uniqueNum.get() will be thread-local even though uniqueNum is static
      private static final ThreadLocal <Integer> uniqueNum = new ThreadLocal <Integer> () {
           @Override protected Integer initialValue() {
                return uniqueId.getAndIncrement();
           }
      };

      public static int getCurrentThreadId() {
           return uniqueNum.get();
      }
 }

同步的作用是防止两个线程同时进入同步的代码块。它也与线程之间的共享变量有关,但在相反的情况下 - 当您希望它们共享时。如果没有同步,您从一个线程所做的更改可能对其他线程可见,也可能不可见(参见此处此处

于 2013-05-29T08:25:30.627 回答
1

如果我理解正确,您可能应该查看final修饰符:

private final String s;

这确保s无法修改,因此您的线程将无法更改其值。

还要确保您的线程不会尝试修改他们不应该修改的值,而是复制它们。

于 2013-05-29T08:18:54.663 回答
0

如果要使用静态变量,则应在同步方法内的类对象上使用同步块。

public abstract class ConsumerIF implements Runnable {

  public static Element root = null;
  public static String name = null;
  public static String type = null;
  public static String location = null;

  public final synchronized void reconfigure() throws FatalDistributionException {

     synchrnized(ConsumerIF.class) {
        Document doc = builder.build(new StringReader(xmlCollector));
        root = doc.getRootElement();
        Element nameElement = root.getChild("name");
        Element typeElement = root.getChild("type");
        Element locationElement = root.getChild("location");
        Element scheduleElement = root.getChild("schedule");

        if (nameElement != null && typeElement != null && locationElement != null){
            name = nameElement.getTextTrim();
            type = typeElement.getTextTrim();
            location = locationElement.getTextTrim();
        }
     }
  }

}

确保所有静态变量都是从同步方法/块访问的,class object而不是实例变量或this实例。您使用的同步方法适用于this实例意味着您正在调用该方法的当前对象和静态变量由所有对象共享。

于 2013-05-29T09:05:30.317 回答