Java multithreading creation and running

Posted by poseidix on Wed, 10 Nov 2021 15:59:44 +0100

Process is the basic unit of system resource allocation and scheduling. Thread is the smallest unit of program running.
Multiple threads in a process will share process resources, which will lead to a series of data security and consistency problems. We need to seriously learn the relevant knowledge of concurrent system to ensure the security of critical zone resources.

So how does java implement multithreading?

java implements such a class called Thread, which is the Thread object of java

Entering the Thread source code, you can see that the source code provides two ways to create multithreading

Method 1: inherit Thread class

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

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


PrimeThread p = new PrimeThread(143);
p.start();

Method 2: inherit Runnable interface

 class PrimeRun implements Runnable {
     long minPrime;
     PrimeRun(long minPrime) {
         this.minPrime = minPrime;
     }

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

Write the code we want to run to the run() method, so that the new thread will execute the code in the run() function body

If we use the inheritance Thread class, the defect lies in the single inheritance limit of java. After implementing the Runnable interface, we can inherit other classes to achieve more functions and better scalability.

As you can see from the Thread source code, there are many construction methods

among

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

We can see that we only need to pass an instance that implements the Runnable interface to implement multithreading. Therefore, I randomly found a class that implements the Runnable interface to experiment. Yes.

 TimerTask timerTask = new TimerTask() {
     @Override
     public void run() {
         for(int i=1;i<=20;i++){
             System.out.printf("I am TimerTask-1:%d\n",i);
         }
     }
 };
 
 Thread threadThree = new Thread(timerTask);
 threadThree.start();

In the Thread source code, there are such fields

    /* What will be run. */
    private Runnable target;
    

The init() method will be called in the constructor, and the init() method will have the following code

this.target = target

The Thread class overrides the run() function

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

Therefore, the Thread.run() method actually uses the run() method that we passed in to implement the instance of the Runnable interface

Full code:

import java.util.TimerTask;

public class ThreadTest {

    public static class MyThread extends Thread{

        @Override
        public void run(){
            for(int i=1;i<=20;i++){
                System.out.printf("I am MyThread:%d\n",i);
            }
        }

    }

    public static class RunnableTest implements Runnable{

        @Override
        public void run() {
            for(int i=1;i<=20;i++){
                System.out.printf("I am RunnableTest:%d\n",i);
            }
        }
    }



    public static void main(String[] args){

        MyThread thread = new MyThread();
        thread.start();

        RunnableTest runnableTest = new RunnableTest();
        Thread threadTwo = new Thread(runnableTest);
        threadTwo.start();

        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                for(int i=1;i<=20;i++){
                    System.out.printf("I am TimerTask-1:%d\n",i);
                }
            }
        };
        TimerTask timerTaskCopy = new TimerTask() {
            @Override
            public void run() {
                for(int i=1;i<=20;i++){
                    System.out.printf("I am TimerTask-2:%d\n",i);
                }
            }
        };
        Thread threadThree = new Thread(timerTask);
        threadThree.start();
        Thread threadFour = new Thread(timerTaskCopy);
        threadFour.start();
    }
}

The experimental results are as follows. If the feeling is not obvious, the range of i traversal can be increased

In the beauty of concurrent programming, the author also recommends FutureTask, which can return a result after the task is executed.

The content of the article comes from the induction and sorting of network materials and books and your own practice. If you have any mistakes or deficiencies, please don't hesitate to give advice.