The previous section covered the basics of threads and processes, but for Java, threads are probably more than that, so the next series of articles will focus on threads.

Create a thread

The way threads are created is a cliche and one of the most popular interview questions. There is a lot of talk on the web about implementing a Runnable interface and implementing a Callable interface. This is not a mistake, but it depends on the perspective. But this kind of detail actually does not need to care too much, do not get to a dead end.

Implement the Runnable interface

Implement the Runnable interface and then override the run() method, which defines how and what the thread does.

public class ImplementsRunnable implements Runnable {

    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "------Runnable thread working...");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            new Thread(newImplementsRunnable()).start(); }}}Copy the code

In the main method, 50 threads are started. To start a Thread is to create a new Thread and pass in the class that implements the Runnable interface. Now let’s see what happens

It can be seen that although we create threads in order, the order of execution of threads is controlled by the CPU, which can be said to be uncontrollable, and it is in this way that the multithreading is running.

Implement Callable interface

What needs to be rewritten once the interface is implemented is the call() method

public class ImplementsCallable implements Callable {

    @Override
    public Object call(a) {
        System.out.println(Thread.currentThread().getName() + "--------callable thread working");
        return "Implement callable, return value";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i = 0; i < 50; i++) {
            ImplementsCallable callable = new ImplementsCallable();
            FutureTask<String> task = new FutureTask<String>(callable);
            newThread(task).start(); System.out.println(task.get()); }}}Copy the code

It is worth noting that there are no overloaded constructors with Callable arguments in the Thread class; they are basically Runnable

FutureTask implements the RunnableFuture interface, which in turn inherits Runnable and Future.

The main difference between the Runnable interface and the Callable interface is that the Callable interface has a return value. What are the scenarios for this return value? For example, in the CASE of an HTTP call, a result needs to be returned. How do I get the return value, using the get() method in FutureTask, and see what happens

There is an interesting problem here. When I comment line 14 and run it, I get the following result: the thread is disordered, which is exactly what I expect.

However, when I keep line 14 of code for several times, the following result will appear, the thread has become orderly, if there is a friend who knows why can leave a message

Thread class inheritance

After inheriting Thread, Idea doesn’t even have to be reminded to override the run() method manually

The overall code is as follows

public class ExtendsThread extends Thread{
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "-------- Thread inheriting Thread working");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            newExtendsThread().start(); }}}Copy the code

The code is relatively simple, so let’s take a look at the result, as expected

The implementation interface is preferred because Java does not support multiple inheritance. If you inherit Thread, you cannot inherit other classes, but you can implement multiple interfaces. And inheriting the entire Thread class is bloated in terms of performance overhead.

Common thread methods

There are many methods related to threads. Here are four common methods.

start

Start () is used every time a thread is started. What is the difference between run() and start()

public class CommonMethod {
    public static void main(String[] args) throws InterruptedException {
       	startRunExample();
    }

    //start,run
    public static void startRunExample(a) {
        new MyThread().start();
        newMyThread().run(); }}class MyThread extends Thread {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + " is running"); }}Copy the code

Create a new class, then create an inner class that inherits Thread, calls the start() and run() methods, and calls the wrapped methods inside the main function. Let’s see what happens.

You can see that one thread name is the main thread and one is the child thread, so the start() method starts a thread that then executes the contents of the run() method. But if you use the run() method directly, the main thread simply executes the contents of the run() method without starting a new thread.

sleep

Sleep allows the current thread to sleep, freeing the CPU for other threads to execute.

public class CommonMethod {
    public static void main(String[] args) throws InterruptedException {
// startRunExample();
        sleepExample();
// yieldExample();
// waitExample();
        
    }

    / / omit start, run
    
    //sleep
    public static void sleepExample(a) throws InterruptedException {
        new MyThread().start();
        Thread.sleep(3000);
        System.out.println(Thread.currentThread().getName() + " is running"); }}class MyThread extends Thread {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + " is running"); }}Copy the code

For example, if I start a new Thread, but I let the main Thread sleep for 3s before running, the result should be thread0 is running and 3s after main is running.

For comparison, I’ll comment out the sleep code and look at the result a few more times

You can see that the results of the two threads are coming out almost at the same time, but which one comes before and which one comes after is out of our control in this case.

yield

Yield is when a programmer suggests that the computer cede CPU usage from the current thread to another thread, but if the CPU doesn’t care about us, it’s a different matter. In plain English, it transitions from Running state to Runnable state.

Again, it is recommended that the computer suspend the current thread and execute another thread, but whether or not to do so is up to the computer.

Create another inner class YieldThread

public class CommonMethod {
    public static void main(String[] args) throws InterruptedException {
// startRunExample();
// sleepExample();
        yieldExample();
// waitExample();
        
    }

    / / omit start, run
    
    / / omit the sleep
	
    //yield
    public static void yieldExample(a) throws InterruptedException {
        YieldThread yieldThread = new YieldThread();
        Thread thread = new Thread(yieldThread, "thread1");
        Thread thread1 = new Thread(yieldThread, "thread2"); thread.start(); thread1.start(); }}class YieldThread extends Thread {

    @Override
    public void run(a) {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " is running " + i);
            if (Thread.currentThread().getName().equals("thread1")) {
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() + " yield "+ i); }}}Copy the code

This is not an exact example, but you can see that the logic of a run is that each thread runs 10 times, producing a running and a yield each time. But when we add thread.yield (), the expected result is

thread1 is running
thread2 is running
thread2 yield
thread1 yield
Copy the code

Thread1 yields the running statement to the CPU. The CPU selects the logic of thread2 and thread1 yields the running statement to the CPU

And then let’s see if we can do what we expect

As you can see, only part of the result is expected when we remove the thread.yield () line

Yes, you’ll find this happening occasionally, but not as often. Because the two threads might be running in parallel, rather than concurrently (alternating), both execute the RUNNING statement at the same time, followed by yield from thread 2 and yield from thread 1.

Here is not necessarily accurate, so it is not quite accurate examples, if there is a better understanding and examples can leave a message!!

wait

The following example is a little more controllable than the previous yield, which is a suggestion, and the latter can be said to be coercive. Suspends the thread from Running to Block and does not execute until it is woken up by an external force.

public class CommonMethod {
    public static void main(String[] args) throws InterruptedException {
// startRunExample();
// sleepExample();
// yieldExample();
        waitExample();
        
    }

    / / omit start, run
    
    / / omit the sleep
	
    / / omit yield
    
    //wait
    public static void waitExample(a) {
        WaitThread waitThread = new WaitThread();
        Thread thread1 = new Thread(waitThread, "thread1");
        Thread thread2 = new Thread(waitThread, "thread2"); thread1.start(); thread2.start(); }}class WaitThread extends Thread {

    @Override
    public void run(a) {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " is running " + i);
            if (Thread.currentThread().getName().equals("thread1")) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
Copy the code

The logic is the same, except that thread.yield () is replaced with wait(). Normally a Thread named thread1 executes once and then stops executing. Let’s see what happens

And expected results are the same, and also an error Java lang. IllegalMonitorStateException.

Creation is not easy, if it is helpful to you, welcome to like, collect and share!