1

I have two different subprocess running two different commands in two different threads.the second thread updates a value in a static variable and the first thread takes the value and uses it.

The flow should be like this : Thread2 updates static variable and thread1 takes up the value from the static variable and then prints it.. but the flow that's happening is thread1 picks up the value from the static variable first. In this case it has a null value and then thread2 updates the value.

Both the threads are running in parallel, i am using ExecutorService class to do this. I'm using Runtime class to run the command and a while loop to read the outputs from the Stream continiously on both threads.

Thread1 keeps on giving (X,Y) values , Thread two gives out the value only when it gets a text.

Output I'm getting :

(12, 123) null --> thread2 didn't get any value so it doesnt update, thread1 would get null from the static variable
(123,334) null --> thread1 picks up the value from the static variable and uses it, thread2 then updates value "Hello" to static variable
(134,654) "Hello" --> thread1 picks up "Hello" and uses it, thread2 then updates value "World" to static variable

Expected output:

(12, 123) null --> thread2 didn't get any value so it doesnt update, thread1 would get null from the static variable
(123,334) "Hello" --> thread2 updates value "Hello" to static variable, thread1 picks it up and uses it
(134,654) "World" --> thread2 updates value "World" to static variable, thread1 picks it up and uses it

i've used a volatile variable too but the output didn'y change. I'm i missing something here? Please help...

  • sounds like you should be using a blockingQueue https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html – Scary Wombat Oct 25 '18 at 06:19
  • better make static variable volatile. using static variable in multi threading [https://stackoverflow.com/questions/8432327/static-variables-and-multithreading-in-java](https://stackoverflow.com/questions/8432327/static-variables-and-multithreading-in-java) – Pandey Amit Oct 25 '18 at 06:27
  • I've used a volatile variable too but it seems like thread1 runs first and then thread2 runs... Thats the reason thread1 picks up null from the variable and then thread2 is updating the variable. – Nishanth Gunupudi Oct 25 '18 at 06:32
  • *seems like thread1 runs first and then thread2 runs* - what are doing to try to control this? – Scary Wombat Oct 25 '18 at 06:50
  • @ScaryWombat nothing infact, can i control it some how so that thread2 runs first and then thread1 runs next, would solve the issue i feel... – Nishanth Gunupudi Oct 25 '18 at 06:53
  • @ScaryWombat i have tried using blockingQueue but since tread2 only puts the value when it gets the text and thread1 keeps on checking the queue for the value, itthrows a NullPointerException.... – Nishanth Gunupudi Oct 25 '18 at 07:51
  • Please post the code in question, otherwise answers will just be guesswork. – TwoThe Oct 26 '18 at 14:16

2 Answers2

0

You can use java.util.concurrent.Semaphore(as of Java 5) to control the number of threads simultaneously accessing a variable they have in common.You instantiate this class with the number of threads(which have called acquire()) allowed to use what they have in common and if you pass 0, it means none of them can modify it.

public class Threaad extends Thread{
volatile static String string;
public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(0);
    Thread writer = new Write(semaphore);
    writer.setName("writer");
    Thread reader = new Read(semaphore);
    reader.setName("reader");
    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(writer);
    service.execute(reader);
    service.shutdown();
}
}
class Write extends Thread{
    private Semaphore semaphore;
    Write(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Threaad.string = String.valueOf(i);
            semaphore.release();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Read extends Thread{
    private Semaphore semaphore;
    Read(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                semaphore.acquire();
                System.out.println(Threaad.string);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
AlirezaAsadi
  • 793
  • 2
  • 6
  • 21
  • Thanks for the reply, i've tried to implement it but the problem still persists. Thread1 takes up the value from the variable and then prints it. Since Thread2 put the value only when it gets a value and Thread1 keeps on trying to acquiring and it, thread1 doesnt print anything.. – Nishanth Gunupudi Oct 25 '18 at 09:07
  • You have to be more precise. I can't clearly understand what you want. Show us your code and I will help. – AlirezaAsadi Oct 25 '18 at 10:30
  • okay, what i want is simple. there are two methods running two different commands simultaneously in the background. M1 and M2 suppose. M1 keeps on giving u the coordinates (X,Y) as the user taps on a device. M2 will only print when user enters some text on the device. so when ever M2 gets the text, it puts the text in a static variable and M1 constantly keeps a track of the variable, if it gets a null then it jus assumes user didnt input any text, but if the variable has some text that means user has put some text and then M1 picks the text from the static variable and continues... – Nishanth Gunupudi Oct 25 '18 at 11:43
  • maybe your problem with printing to the output is because of the buffered optimization of the "System.out.println()" method . Use "System.err.println()" instead. – AlirezaAsadi Oct 25 '18 at 16:35
0

Things not to do when using threads: writing and reading the same variable without proper synchronization. You violate this rule and therefore you run into the expected problems of undefined results.

Imagine the following execution flow:

T1: set var to "Hello"
T2: checks var and notices it is a String, proceeds to print it.
T1: set var to null
T2: prints var. (which is already null again)

A possible solution is that T2 first copies the value to a thread-local variable and then proceeds working on that one, i.E.:

while (running) {
  final String localString = staticString;
  if (localString != null) {
    System.out.println(localString);
  }
}

This way you create a "snapshot" of the current value of the variable, and will actually output what has been snapshotted at that moment. However this still is no valid way to synchronize between threads, because the snapshot state is completely random. Imagine that the following happens:

T1: set var to "hello"
T1: set var to null
T2: checks var, it is null, do nothing.
T1: set var to "world"
T1: set var to null
T2: checks var, it is null, do nothing.

When working with Threads you need to keep in mind that the state of any thread at any time is always undefined, unless you enforce it.

There are simple ways to enforce a specific state i.E. synchronized which basically means "Put the whole thing on hold so I can do my work", however that is quiet inefficient, as there is no point of working in parallel if you constantly put everything on hold.

A much better way to approach Threading is from an architectural point of view i.E. by using triggers. In your case the writer-thread could have a queue with only relevant information (the strings to output), and the producer-thread will put strings into that queue:

T2: checks queue, it is empty, do nothing.
T1: t1.put("Hello")
T2: checks queue, it contains "Hello", print that.
T2: checks queue, it is empty, do nothing.
T2: checks queue, it is empty, do nothing.
T1: t1.put("World")
T2: checks queue, it contains "World", print that.

I recommend to read through the concurrent package to learn about the tools Java offers. Almost all problems can be easily solved using those.

TwoThe
  • 13,879
  • 6
  • 30
  • 54