Thread class for exercises I just felt a sting as for the first time, I copy-pasted code blocks, and made very little change to it, to overload it. It works fine, but I have 3 constructors that are basically copy-pasted. I'm hoping there is a smarter way to do this.

This simply creates a thread and runs it with 1, 2 or 3 arguments, and then prints numbers to System.out using that thread. I will include an example usage below. The code doesn't strike me as bad of itself, but the sheer repetition is really bugging me. All criticism welcome. 

import java.lang.Thread;

/**
 * Generic class that creates a thread and then loops and prints numbers to stdout.
 */
public class NumLoopThread implements Runnable {
    Thread thread;
    private String threadName;
    private int sleepTime = 400;
    private int numLoops = 10;

    /** Default constructor with threadName */
    public NumLoopThread(String threadName) {
        this.threadName = threadName;
        thread = new Thread(this, threadName);
        thread.start();
    }
    /** Extra constructor with threadName and sleepTime */
    public NumLoopThread(int sleepTime, String threadName) {
        this.sleepTime = sleepTime;
        this.threadName = threadName;
        thread = new Thread(this, threadName);
        thread.start();
    }
    /** Extra constructor with threadName, sleepTime, and numberLoops */
    public NumLoopThread(int sleepTime, String threadName, int numberLoops) {
        this.sleepTime = sleepTime;
        this.threadName = threadName;
        this.numLoops = numberLoops;
        thread = new Thread(this, threadName);
        thread.start();
    }
    /** Run the thread from start() */
    public void run() {
        System.out.printf("%s starting%n", threadName);
        try {
            for(int i = 0; i &lt; numLoops; i++) {
                Thread.sleep(sleepTime);
                System.out.printf("%s, i = %d%n", threadName, i);
            }
        } catch(InterruptedException exc) {
            exc.printStackTrace();
        }
        System.out.printf("%s ending%n", threadName);
    }
}


Example usage I wrote for an exercise (feel welcome to also criticize this, if you want). Looks like this paste after it's ran.

public class ThreadIsAlive {
    public static void main(String[] args) {
        System.out.println("Main thread starting");
        // create 3 running threads
        NumLoopThread t1 = new NumLoopThread(400, "t1");
        NumLoopThread t2 = new NumLoopThread(400, "t2");
        NumLoopThread t3 = new NumLoopThread(400, "t3");

        do {
            System.out.print(".");
            try {
                Thread.sleep(100);
            } catch (InterruptedException exc) {
                exc.printStackTrace();
            }
        //wait until all threads terminate:
        } while (t1.thread.isAlive() ||
                 t2.thread.isAlive() ||
                 t3.thread.isAlive());
        System.out.println("Main thread ending");
    }
}
Chained constructors.
I find it interesting that you described the single-parameter constructor as your &quot;default&quot; one, and the others as &quot;extras&quot;. It's usually the other way around: the constructor that initializes all immutable fields is the &quot;main&quot; one, and any other constructor that works off default values would be &quot;convenience&quot; constructors.

public NumLoopThread(int sleepTime, String threadName, int numberLoops) {
    this.sleepTime = sleepTime;
    this.threadName = threadName;
    this.numLoops = numberLoops;
    thread = new Thread(this, threadName);
    thread.start();
}


Take out numberLoops, you get this one:
public NumLoopThread(int sleepTime, String threadName) {
    // pasta
}

Take out sleepTime, you get this one:
public NumLoopThread(String threadName) {
    // pasta
}

Looks like threadName should be the first parameter in all 3 constructors, for consistency:
public NumLoopThread(String threadName, int sleepTime) {
    // pasta
}


public NumLoopThread(String threadName, int sleepTime, int numberLoops) {
    this.sleepTime = sleepTime;
    this.threadName = threadName;
    this.numLoops = numberLoops;
    thread = new Thread(this, threadName);
    thread.start();
}

That way when you look at your overloads, they all look like they naturally extend each other, in some sort of chain.
You already have your defaults:

private int sleepTime = 400;
private int numLoops = 10;


Consider making them static final, and single-purpose:
private static final int defaultSleepTime = 400;
private static final int defaultNumLoops = 10;

And since the actual fields are only ever assigned in a constructor, they should be marked final, too:
private final int sleepTime;
private final int numLoops;

Use this(); as the first instruction in the body, to &quot;chain&quot; the constructors:
public NumLoopThread(String threadName, int sleepTime) {
    this(threadName, sleepTime, defaultNumLoops);
}

public NumLoopThread(String threadName) {
    this(threadName, defaultSleepTime, defaultNumLoops);
}

Voilà, no more pasta!

That said I'm not sure about start()ing the thread in the constructor; it makes your run method a bit misleading. In general it is not a good idea to pass your 'this' reference to to a thread and start it during construction. The thread could then start with an unfinished object. Generally you should leave the starting of the thread to a separate method. (ref)