简体   繁体   中英

Java thread and the run method

I'm writing a Java application that uses some threads. Main method looks like this:

WorkerThread[] thread = new WorkerThread();
for (int i = 0 ; i<10 ; i++) {
    thread = new WorkerThread();
    thread.doStuff();
}

and my WorkerThread looks like this:

class WorkerThread {
    public void run() {
        ...
    }

    public void doStuff() {
        ...
    }
}

The matter is that, obviousely, I call doStuff from the run method it is executed like concurrently with other threads, but if i call doStuff directly from the main it is executid not cocurrently.

Ok, now the question is: is there a way to execute, concurrently, the doStuff method calling it not from the run method, but rather, from the main?

You cannot directly call methods on a Thread object. The only way to get concurrency with a Thread is to invoke its start() method, which in turn calls run() on a separate thread of execution. Calling any other methods directly from main() is just like calling methods on regular non-Thread objects; there's no concurrency, nothing special happens, the methods execute immediately.

It sounds like you're trying to communicate between the main thread and the worker threads. Each thread's run() method is in charge of executing code on that thread. If you can communicate with that run() method then you can control what happens on that thread.

One way to do that is to pass a variable in when you construct the Thread. Save a value that the run() method can examine to determine what to do. For example, below we have an enum that has three possible actions in it. The run() method looks at the enum and decides what to do based on the value that was passed to the WorkerThread() constructor.

class WorkerThread {
    public enum Action { DO_STUFF, MAKE_WIDGETS, FROB_BARS }
    private Action action;

    public WorkerThread(Action action) {
        this.action = action;
    }

    public void run (){
        switch (action) {
            case DO_STUFF:     doStuff();     break;
            case MAKE_WIDGETS: makeWidgets(); break;
            case FROB_BARS:    frobBars();    break;
        }
    }

    public void doStuff()     { ... }
    public void makeWidgets() { ... }
    public void frobBars()    { ... }
}

Now our main() method looks like this. You create WorkerThreads passing in the action to perform, then call start().

WorkerThread[] threads = new WorkerThread[10];
for (int i = 0; i < threads.length; ++i) {
    threads[i] = new WorkerThread(WorkerThread.Action.DO_STUFF);
    threads[i].start();
}

You could do the same thing in myriad different ways. Instead of having one WorkerThread class you could have several different classes with differing run() methods and then instantiate the appropriate sub-class from main().

class DoStuffWorkerThread     extends Thread { ... }
class MakeWidgetsWorkerThread extends Thread { ... }
class FrobBarsWorkerThread    extends Thread { ... }

You can even create anonymous Thread classes right inside main(), if you like. Then the logic can be whatever main() wants.

Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; ++i) {
    threads[i] = new Thread() {
        public void run() {
            doStuff();
        }
    };

    threads[i].start();
}

When you are using thread.doStuff(); you are not using Threading, as to use threading you will have to call thread.start() method, which will internally call run() method internally.

 Thread[] threads = new Thread()[10];
    for (int i = 0 ; i<10 ; i++) {
        if ( i<5) {
          threads[i] = new Thread(new WorkerA());
        } else {
          threads[i] = new Thread(new WorkerB());
        }
        threads[i].start();
    }

At first, you're creating an array but don't use it right. You can not assign a Object to an array? Then you have to call the start() method to execute the thread in background and invoke his run method.

Your Worker's should look like this:

class WorkerA implements Runnable {            

    public void run (){
        ...
        // put here your code from doStuff in one Version
        ...
    }

}

class WorkerB implements Runnable {

    public void run (){
        ...
        // put here your code from doStuff in an other Version
        ...
    }

}

Instead of calling the thread[i].start() in your loop, you can now call it anywhere with the reference to your array.

You can use Runnable for that.

// Dictate what work needs to be done
Runnable work = new Work(); // or new OtherWork();

Thread thread = new Thread(work);
thread.start();

class Work implements Runnable {
    public void run(){
        System.out.println("do stuff");
    }
}

class OtherWork implements Runnable {
    public void run() {
        System.out.println(" do other stuff");
    }
}

EDIT :
It is recommendable to use thread pools instead of creating (and discarding) threads for each task. This is because there is some overhead in creating/discarding threads, and it also makes it easier to manage at what concurrency the tasks should be done etc.

Anyways, you could create your thread pool by yourself using Thread class, but that's a lot of work and it's hard to get it right. Instead, it's best to use the ready made solution available in the JDK. You can use it as follows:

ExecutorService threadPool = Executors.newFixedThreadPool(4);
threadPool.execute(new Work());
threadPool.execute(new OtherWork());

// After submitting all your task (or when your application wants to terminate)
// You should call shutdown() on the thread pool so that the JVM can exit
threadPool.shutdown();

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