lulu88
lulu88

Reputation: 1714

Java multithreading and global variables

I have a Java class that starts up 2 separate threads. The first thread starts up fine and all the variables are correct.

When I start the second thread the global variables from thread one changes to the values set in thread 2.

I have tried adding synchronized blocks where the global variables are updated, but this did not work.

Is there a way to solve this issue? I want each thread to start up and use its own values without interference in other thread values.

EDIT:

Snippet of my Thread class:

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

      }
  }

Upvotes: 11

Views: 50712

Answers (5)

Mifeet
Mifeet

Reputation: 13608

If you do not want your variable shared, then do not use a global variable (you probably mean static in Java). Create a new field with a new object initialized when your thread starts. Example:

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

If you really need to access your objects locally to your thread across different pieces of code, then use 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();
      }
 }

What synchronization does is that it prevents two threads to enter the synchronized block of code at the same time. It's also related to sharing variables between threads but in the opposite case - when you want them shared. Without synchronization, your changes from one thread may or may not be visible to other threads (see here and here)

Upvotes: 2

Jatin Sehgal
Jatin Sehgal

Reputation: 966

If you want to use static variables then you should use synchronized blocks on the class object inside your synchronized methods.

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

}

Make sure all your static variables are accessed from a synchronized method/block on the class object rather than on an instance variable or this instance. The synchronized method you have used is applicable on this instance means the current object with which you are calling the method and the static variables are shared by all the objects.

Upvotes: 0

koljaTM
koljaTM

Reputation: 10262

Static variables are shared between all Threads, thats what makes them static. If you want to use different values, either use ThreadLocals or (much better), use different objects with non-static variables in the differrent threads. Without further code it's difficult to say more though.

Upvotes: 19

Djon
Djon

Reputation: 2260

If I understand correctly, you should probably look at the final modifier:

private final String s;

This ensures that s cannot be modified, thus your threads won't be able to change its value.

Also make sure that your threads do not attempt to modify values they shoudl not, copy them instead.

Upvotes: 1

Brian Agnew
Brian Agnew

Reputation: 272207

Synchronisation merely controls the threads' access to the shared state.

If you want separate state per thread then you need to either declare different instances of that information (e.g. classes) per thread. e.g. simply instantiate a new object in each Thread's run() method, or perform a copy of the structure in question (e.g. a deep copy of a collection)

An alternative is to investigate ThreadLocal, in which each Thread will have a different copy of a nominated resource.

Upvotes: 6

Related Questions