1

When I try to use methods inside a class in which I extend Thread it does not receive the methods after the run.

My class:

public class PassPhraseValidator<E> extends Thread {

    private List<E> list;
    private boolean isValid;
    private String passPhrase;
    public PassPhraseValidator(List<E> list) {
        this.list = list;
    }

    public String getPassPhrase() {
        return passPhrase;
    }

    public boolean isValid() {
        return isValid;
    }

    public void run(){
        this.passPhrase = Arrays.toString(list.toArray());
        this.isValid = list.stream().filter(e -> Collections.frequency(list, e) > 1).count() == 0;
    }
}

So when I execute this class like this:

PassPhraseValidator<Integer> validIntegerPassPhrase = new PassPhraseValidator<>(Arrays.asList(12, 18, 15, 32));
validIntegerPassPhrase.start();
System.out.println(validIntegerPassPhrase.getPassPhrase() + " valid: " + validIntegerPassPhrase.isValid());

It gives me false while it should be true because the run function wasn't ran yet.

What am I doing wrong here? How can I make multithreading part of this? It does work when I directly put it inside the methods.

Sinan Samet
  • 6,432
  • 12
  • 50
  • 93
  • The default for a boolean field is false! It starts with that value! Beyond that, there are potential visibility issue in multi threading! – GhostCat Aug 16 '18 at 17:11

2 Answers2

1

The last System.out.println statement does not wait for your thread (the run function) to complete.

One way to wait for its completion is to call the join method

validIntegerPassPhrase.join();  //Need to handle the InterruptedException it might throw
System.out.println(validIntegerPassPhrase.getPassPhrase() + " valid: " + validIntegerPassPhrase.isValid());
Thiyagu
  • 17,362
  • 5
  • 42
  • 79
  • Thank you that works! I had a hunch it ran before the run() but I didn't know how to handle it. – Sinan Samet Aug 16 '18 at 17:16
  • Calling `run` will make it run on the main thread itself (which defeats the purpose of a Thread) – Thiyagu Aug 16 '18 at 17:19
  • That confuses me a little. You mean I shouldn't do it this way? Should I just put `return Arrays.toString(list.toArray());` for example inside `getPassPhrase()`? – Sinan Samet Aug 16 '18 at 17:28
  • 1
    I meant if you do `validIntegerPassPhrase.run()`, then no new thread will be created. The `run` logic will run on the main thread itself. You can print the name of the thread by `Thread.currentThread().getName()` – Thiyagu Aug 16 '18 at 17:32
  • 1
    See https://stackoverflow.com/questions/8579657/whats-the-difference-between-thread-start-and-runnable-run – Thiyagu Aug 16 '18 at 17:32
1

Explanation

What you are doing is called multithreading. This allows multiple threads to execute code concurrency or in parallel. Programs run on something called the main thread. This means one thread is executing all code systematically; one instruction after another. When introducing another thread like you are, the program execution is being done on different logic at the same time. So, when you execute the start() method on your implementation of the thread class, you are causing it to execute it's respective run() method in the background until; it completes, an exception is thrown, the application is shutdown, or the thread is stopped.

Lets step through your code and analyze the scenario.

  1. Thread object is instantiated by the main thread. Lets call this new thread thread2.

  2. thread2 is started by the main thread.

  3. thread2 and the main thread are both running in parallel. This means code is being executed by both of them (for simplicity) at the same time.

  4. Two possibilities could be occurring for this issue; Java Memory Barrier (beyond the scope of this question but more reference here) or timing. The main thread is most likely reading the print statement before thread2 can finish it's respective run() method.


Solution

  1. An approach may be not to use multi-threading at all. The creation of threads is quite a costly operation and should not be done frequently. Typically, in app's that require multi-threading thread-pools are utilized instead.

  2. Utilize the join() blocking function. Join forces the calling thread (in this case it would be the main thread) to wait for the respective thread to finish execution before continuation.

  3. Implement the thread with use of Promise. This object is a wrapper for the Future class, allowing for the get() method to be blocking. This means the calling thread (in this case it would be the main thread) to wait for the respective thread to finish execution before continuation. An example of Promise's can be found here.

Impurity
  • 1,037
  • 2
  • 16
  • 31
  • Thank you this clarifies a lot. I have to use multithreading as it is the purpose of the exercise and my goal was to use this with multiple threads ofcourse. In my version this is implemented now and works like I want it! – Sinan Samet Aug 16 '18 at 18:21
  • Of course! I'm glad I was able to assist in your learning and understanding. – Impurity Aug 16 '18 at 18:24