简体   繁体   中英

Overloading Thread.start()

Assuming I have a class extending Thread.

So from what I know so far:

  • the run() method is treated just like an ordinary method when being called directly and it will not cause the JVM to create a new thread for it.

  • in order to have it work as intended, the start() method must be called, which, in turn, calls the run() method, after some OS dark juju magic takes place.

My question is:

Is there any way someone can overload start()/run() and keep the normal behaviour?

Note: you are mistaking curiosity for stupidity, no need to be rude.

You could do this if you subsclass Thread , by calling Thread 's start or run method, respectively. However, if you intend to pass parameters to the underlying code, I suggest you to implement a Runnable instead and keep the parameters in its state:

class MyRunnable implements Runnable {

    private final int a;
    private final int b;

    public MyRunnable(int a, int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public void run() {
        // do something with a and b
    }   
}

a and b are sort of "parameters in this sample. You can pass an instance to a Thread in its constructor , and then just start it. By the way this is sort of an implementation of the Command Pattern .

Of course:

class StupidThread extends Thread {
    @Override
    public void start() {
        run();
    }
}

But why would you do this? You cannot do this globally for every thread created in JVM, you are however free to use StupidThread wherever you want.

You can override start/run methods in Thread because start and run methods in Thread class are not final methods. Ex : isAlive(), stop(), suspend(), join() are final methods. So U can't override.

public class TempThread extends Thread
{
    @Override
    public synchronized void start() {
        // TODO Auto-generated method stub
        super.start();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
    }       

    public static void main(String[] args) 
    {
        TempThread t = new TempThread();
        t.start();
        t.run();
    }
}

But as you asked about Overload

You can overload any of these methods.

Ex :

public class TempThread extends Thread
{
    @Override
    public synchronized void start() {
        // TODO Auto-generated method stub
        super.start();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
    }

    // ******** Overload **********
    public synchronized void start(int i) {
        // TODO Auto-generated method stub
        super.start();
    }

    // ********* Overload **********
    public void run(int i) {
        // TODO Auto-generated method stub
        super.run();
    }

    public static void main(String[] args) 
    {
        TempThread t = new TempThread();
        t.start();
        t.run();
    }   
}

Note : Check the differences between overriding and overloading. That gives you better understanding about the issue.

If you want to use an overload of the run() method you'll have to do this from the body of the run() method. Of course if you're doing that, you might as well not call the method run() .

As for overloading the start() method. It could be thought of as a JNI method that calls pthread_create() or similar and then calls your run() method. In reality it's probably implemented differently for performance reasons. You're best not meddling with it. You could however consider overloading the thread constructor as is shown in the first example on this page: http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html .

 class PrimeThread extends Thread {
     long minPrime;
     PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }

One alternative is to create an anonymous instance of Runnable . This will allow you access final local variables and final parameters (of the method that creates the Runnable ) and the fields of class that creates the Runnable . Additionally, you also get access to the methods of the enclosing class.

eg.

class SomeClass {

    // constructor, getter and setter not included for brevity

    private String field;

    public void startNewThread(final String parameter) {
        final double local = Math.random();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(field + parameter + local);
            }
        }).start();
    }
}

WARNING: As the enclosing class may be modified by another Thread so directly accessing non-final fields is discouraged as you make get an out of date value. Either make access by a synchronised getter or only access final fields (whose contents are immutable if objects).

I found that the method given above based on calling super.start() didn't parallelize as expected. One workaround to this is to pass your arguments as member variables to a subclass of thread:

public class MyRunnable extends Thread {
    private int id=0;
    MyRunnable(int i){
    this.id=i;
}


public void run() {
    System.out.println("Starting run: " + (id+1));
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Finishing run: " + (id+1));
}

public static void main(String args[]) {
    MyRunnable threadArray[] = new MyRunnable[5];
    for (int j = 0; j < 5; j++) {
        threadArray[j] = new MyRunnable(j);
        threadArray[j].start();
    }
}


}

Obviously I've used a constructor here, but you could use a setter method before calling the run() method.

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