What if I use the Thread constructor without any parameter? Will my thread do nothing?
As specified earlier, The Thread class implements the Runnable Interface so you can also make a custom Thread class which won’t need a Runnable to start.

A Custom Thread class:

public class CustomThread extends Thread{
@Override
public void run() {
// What to do when the thread is started
}
}

Starting the custom Thread:

// Creating the custom thread
CustomThread customThread = new CustomThread();
// Starting the thread
// Careful: if you use the Run() method directly
// the task won't run in another thread!
customThread.start();

So why bother with a Runnable if we can do without? Two main reasons:

Separation of concerns: Not mixing the thread management part and tasks processed will make the project easier to create, understand and maintain.

Inheritance: Implementing the Runnable interface let your class extends from another class which wouldn’t be possible if already extending the Thread class.

Thread methods

Once you have a thread up and running, you still have some possibilities in order to interact with it.

Sleep

When a thread is put to sleep it will totally stop working for a certain amount of time (in milliseconds).
The sleep operation throws InterruptedException that should be managed in a Try-Catch block.

// Putting the current Thread to sleep for 1sec
Thread.sleep(1000);

Yield

The yield method will pause momentarily the current thread to allow another thread that is ready to run to be processed by the processor.
This allow a thread not to overflow a processor when working on a resource-heavy task.

// Yielding the current Thread
Thread.yield();

Join

The join method all to pause the current thread until the specified thread finished its execution.

Interrupt

The interrupt method will ask to a thread to stop whenever possible. The interruption have to be managed on the Run method as you can’t stop a thread directly which would be too unsafe depending on the operation(s) in progress.

Two methods in order to manage a thread interruption in a Runnable:

The interrupted method

while(!Thread.interrupted())
{
// As long as the thread isn't interupted
// Do something...
}

Synchronization

Working with multiple threads means some of them might try to interact with the same object or resources. When that happens some errors or unexpected behaviors often happens if the code is not thread-safe.

To avoid this we use synchronization which will basically forbid multiple threads to access the same part of code, method, or object at the same time.

The ReentrantLock class

The ReentrantLock class allows to lock and unlock at any place in the code.

private static ReentrantLock lock = new ReentrantLock();
public static void LockExample()
{
lock.lock();
// Do something...
// This code will be executed
// by only one thread at a time.
lock.unlock();
}

Synchronized keyword

The Synchronized keyword allows to lock a whole method or an object.

// Synchronized method
public static synchronized void LockExample()
{
// Do something...
// This code will be executed
// by only one thread at a time.
}

Synchronization on an object:

Object obj = new Object();
synchronized (obj) {
// Do something...
// This code will be run
// by only one thread at a time.
}

Wait method

The wait method allows to pause the thread and release the lock, which means it have to be used in a synchronized block of code.
The wait method manage interruption like other methods and therefor requires to manage InterruptedException.