简体   繁体   中英

Understanding Threads implementing Runnable in java

I'm trying to understand Threads in Java. I've created a thread implementing the Runnable interface, which executes a certain function of a certain class. The following are the Java classes:

MyThread Class

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    private Thread thread;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
        thread = new Thread(this);
        thread.start();
        thread.setName("Thread 2");
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
    public void runThread() {
        thread.run();
    }
}

The DataContainer Class . The function of which I execute in the thread

public class DataContainer {
    private static DataContainer instance = null;
    private DataContainer() {}
    public static DataContainer getInstance() {
        if(null == instance)
            instance = new DataContainer();
        return instance;
    }
    @Override
    public String toString() {
        return Thread.currentThread().getName()+" : __Data__";
    }
}

The main class

public class Launcher {
    public static void main(String[] args) {
        DataContainer dataContainer = DataContainer.getInstance();
        MyThread myThread = new MyThread(dataContainer);

        int i =0;
        while(i++<10) {
            System.out.println("Launcher : "+ dataContainer.toString());
            myThread.runThread();
        }
    }
}

The problem is, in the while loop where is execute the dataContainer.toString() from the main class and the myThread instance, I get the output as they are all running in one thread: main thread . None of the executions in the loop are executed from Thread 2 .

My aim is that, in the while loop, I want myThread.runThread() to be executed under the thread Thread 2 .

EDIT:

Added thread.start() . However, now it gets executed only once? I can't create a new thread every time I want to execute myThread.runThread(). By creating a new thread in the loop, I'd end up creating a bunch of threads. Is this advisable? I want a certain piece of code(say Y) to be executed by a thread(say X). Every time Y has to be executed, it should be done through the thread X.

Solution

This can be a possible solution:

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    private Thread thread = null;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
    public void runThread() {
        boolean threadIsAlive = (null!=thread && Thread.getAllStackTraces().keySet().contains(thread));
        if(null == thread || !threadIsAlive) {
            thread = new Thread(this);
            thread.start();
        } else {
            thread.run();
        }
    }
}

thread.run(); is just calling your Runnable s run method directly, within the current thread's context. You'll get the same result if you're simply called run() in you runThread method.

You need to call thread.start() , this will create a new process thread and eventually call your Runnable s run method

Rather than wrapping a Thread instead a Runnable , which is counterintuitive and generally bad design, you should create Thread and set the Runnable to it when you need to, for example...

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
}

Then you could do something like...

DataContainer dataContainer = DataContainer.getInstance();
MyThread myThread = new MyThread(dataContainer);

Thread thread = new Thread(myThread );
thread.setName("Thread 2");
thread.start();

System.out.println("Launcher : " + dataContainer.toString());

myThread.runThread() will just invoke that method in current thread. If you want that to be executed in new thread, put that call in run method and just call myThread.start() . This starts another thread and calls run method of your runnable object.

When you define a class which implements Runnable, you do not need to have a Thread object in it.

Simplistically

 class myThread implements Runnable {

     @Override
    public void run() {
          // do something
   }
}


new Thread (new myThread ()).start ();

I didn't try to understand your example (too convoluted), but this is a bad idea:

public class Foobar implements Runnable {
    private XType x;
    private YType y;
    private Thread thread;

    public Foobar() {
        x = new XType();
        thread = new Thread(this);   //Not in a constructor!!!
        thread.start();
        y = new YType();
    }

    @Override
    public void run() {
        doSomethingWith(y);       // y can be uninitialized at this point.
        doSomethingElseWith(x);   // x can be uninitialized too!!!
    }
}

This anti-pattern has a name, It's called "leaking this from a constructor." The Foobar constructor starts the new thread, and gives it a reference to the new Foobar instance (ie, this ) before the new object has been fully initialized. The Java language spec makes no guarantees about what the object will look like to the new thread when the object is published in this manner. (Google for "safe publication")

In particular, When the run() method is first entered, any of the object's member variables (including x!!) can appear to be uninitialized from the new thread's point of view.

Best Practice: Don't ever use this in a constructor or in any helper method that is called by the constructor, and also, declare helpers to be final so that a sub-class can't override one and see the un-initialized object that way.

class Foobar {

    Foobar(...) {
        ...don't use "this" here...
        fooHelper(...);
    }

    private final void fooHelper(...) {
        ...don't use "this" here either...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM