Reputation: 1714
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
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
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
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
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
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