Java多线程和全局变量

时间:2013-05-29 08:16:14

标签: java multithreading thread-safety

我有一个Java类,可以启动2个独立的线程。第一个线程启动正常,所有变量都正确。

当我启动第二个线程时,来自线程1的全局变量将更改为线程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();
            }

      }
  }

5 个答案:

答案 0 :(得分:13)

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

答案 1 :(得分:6)

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

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

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

答案 2 :(得分:2)

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

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();
      }
 }

同步的作用是防止两个线程同时进入同步的代码块。它也与在线程之间共享变量有关,但在相反的情况下 - 当你想要它们共享时。如果没有同步,您对一个线程的更改可能会或可能不会被其他线程看到(请参阅herehere

答案 3 :(得分:0)

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

private final String s;

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

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

答案 4 :(得分:0)

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

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实例上访问。您使用的synchronized方法适用于this实例意味着您调用方法的当前对象和所有对象共享静态变量。