Three ways to create threads

Posted by Simon180 on Wed, 22 Dec 2021 20:10:10 +0100

Three ways to create threads?

Answer:

1. Inherit Thread class step1-4

step1: inherit Thread class
public class A_extends_RunningMan extends Thread {
    private String name;
    public A_extends_RunningMan() {
    }
    public A_extends_RunningMan(String name) {
        this.name = name;
    }
step2:  rewrite run method
    public void run() {
        for (int i = 0; i <= 3; i++) {
            System.out.println(Thread.currentThread().getName() + this.name + "Run to No" + i + "Mi La");
        }
    }
}
		step3:  Create this type of object
        A_extends_RunningMan r1 = new A_extends_RunningMan("Xiao Ming");
        A_extends_RunningMan r2 = new A_extends_RunningMan("Xiao Zhang");
        A_extends_RunningMan r3 = new A_extends_RunningMan("petty thief");
        step4: call start Method to start the thread
        r1.start();
        r2.start();
        r3.start();

Advantages: this code is simple and in line with everyone's habits.
Disadvantages: because the inheritance of java classes is single, only one parent class can be specified after extensions. If the current class inherits Thread class, it cannot inherit other classes. If our class already inherits a class, we can no longer inherit the Thread class.

What should I do? Lead out the second method

2. Implement Runnable interface step1-5

step1 realization Runnable Interface
public class B_Runnable_SellTickets implements Runnable {
    private int ticket = 5;
    step 2 make carbon copies run method
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "       Ticket No" + ticket-- + "Zhang");
            }
        }
    }
}
----------------------------------------Execution 1-------------
		step3 establish Runnable Subclass object
        B_Runnable_SellTickets myThread1 = new B_Runnable_SellTickets();
        B_Runnable_SellTickets myThread2 = new B_Runnable_SellTickets();
        step4 establish Thread Class object, set Runnable Subclass object passed to Thread Class object
        step5 call start Method to start the thread
        new Thread(myThread1).start();
        new Thread(myThread2).start();
        
Thread-0       Ticket No. 5
Thread-0       Ticket sheet 4
Thread-0       Ticket sheet 3
Thread-0       Ticket sheet 2
Thread-0       Ticket sheet 1
Thread-1       Ticket No. 5
Thread-1       Ticket sheet 4
Thread-1       Ticket sheet 3
Thread-1       Ticket sheet 2
Thread-1       Ticket sheet 1
-------------------------------------Execution 2----------------
        B_Runnable_SellTickets myThread = new B_Runnable_SellTickets();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
        
Thread-0       Ticket No. 5
Thread-0       Ticket sheet 4
Thread-0       Ticket sheet 3
Thread-0       Ticket sheet 2
Thread-1       Ticket sheet 1
 above ticket The order of output is not necessarily 54321, because the timing of thread execution is difficult to predict

We have three new Thread objects, but only one Runnable object. The three Thread objects share the code in the Runnable object. Therefore, three threads will complete the ticket selling task together.
If we new three Runnable objects and pass them into the three Thread objects as parameters, the three threads will execute the code in their Runnable objects independently, that is, the three threads will sell five tickets respectively.

Implementing the Runnable interface has the following advantages over inheriting the Thread class:
1. It can avoid the limitations caused by the single inheritance feature of Java;
2. Enhance the robustness of the program. The code can be shared by multiple threads. It is suitable for multiple thread areas of the same program code to process the same resource.;
3. Separate the thread object from the thread task object. Reduces coupling and facilitates maintenance

Runnable can share data. Multiple threads can load a runnable instance at the same time. When their respective threads obtain CPU time slices, they start running runnable. The resources in runnable are shared, so using runnable is more flexible.
Personal understanding: multithreading is to avoid waste. Multiple threads can load a Runnable instance at the same time, so that the probability of this divided time slice is high and the execution is faster.

Since three Thread objects jointly execute the code in one Runnable object, it may cause Thread insecurity. For example, the ticket may output - 1 (this is likely to happen if we add Thread hibernation before the System.out... Statement)

public class B_Runnable_SellTickets implements Runnable {
    private int ticket = 5;
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (ticket > 0) {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "       Ticket No" + ticket-- + "Zhang");
            }
        }
    }
}
        B_Runnable_SellTickets myThread = new B_Runnable_SellTickets();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
Thread-0       Ticket No. 5
Thread-1       Ticket sheet 4
Thread-2       Ticket sheet 3
Thread-1       Ticket sheet 2
Thread-2       Ticket sheet 1
Thread-0       Ticket No. 0
Thread-1       Ticket No-1 Zhang
This is due to:
A thread is judging ticket Is 1 > 0 After that, I haven't had time to subtract 1,
Another thread has ticket Minus 1, becomes 0,
Then the previous thread will ticket Minus 1, you get -1 . 

This requires adding synchronous operations (i.e. mutexes) to ensure that only one thread is executing each time at the same time for Operation in the loop.
In the example of executing 1, there is no need to join the synchronization operation, because each thread executes its own Thread Object, there is no case where multiple threads execute the same method together.
public class B_Runnable_SellTickets implements Runnable {
    private int ticket = 5;
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "       Ticket No" + ticket-- + "Zhang");
                }
            }
        }
    }
}
        B_Runnable_SellTickets myThread = new B_Runnable_SellTickets();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
Thread-0       Ticket No. 5
Thread-0       Ticket sheet 4
Thread-0       Ticket sheet 3
Thread-0       Ticket sheet 2
Thread-0       Ticket sheet 1
 Only one thread will execute, and other threads cannot obtain the lock

Auxiliary understanding lock: link.

Runnable is a stand-alone task that performs work, but it does not return any values. If you want the task to return a value after completion, you can implement the Callable interface instead of the runnable interface.
Callable introduced in Java SE5 is a generic type with type parameters. Its parameter types represent the values returned from the method call().

3. Implement callable interface step1-6

In this way, you can get the return value after the thread is executed.

step1 realization callable Interface
public class C_callable_SellTickets implements Callable<Integer> {
	step2: make carbon copies call method
    public Integer call() throws Exception {
        int tickets = 0;
        for (; tickets < 5; tickets++) {
            System.out.println(Thread.currentThread().getName() + "       Ticket No" + tickets + "Zhang");
        }
        return tickets;
    }
}

		step3: establish Callable Subclass object
        C_callable_SellTickets myThread1 = new C_callable_SellTickets();
        C_callable_SellTickets myThread2 = new C_callable_SellTickets();
        step4: establish FutureTask Object, Callable Subclass object passed to FutureTask object
        FutureTask<Integer> futureTask1 = new FutureTask<>(myThread1);
        FutureTask<Integer> futureTask2 = new FutureTask<>(myThread2);
        step5: establish Thread Class object, set FutureTask Object passed to Thread object
        step6: call start Method to start the thread
        new Thread(futureTask1, "Thread 1 with return value").start();
        new Thread(futureTask2, "Thread 2 with return value").start();

        try {
            System.out.println(Thread.currentThread().getName() + " Thread return value: " + futureTask1.get());
            System.out.println(Thread.currentThread().getName() + " Thread return value: " + futureTask2.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
Thread 2 with return value       Ticket No. 0
 Thread 2 with return value       Ticket sheet 1
 Thread 1 with return value       Ticket No. 0
 Thread 1 with return value       Ticket sheet 1
 Thread 1 with return value       Ticket sheet 2
 Thread 1 with return value       Ticket sheet 3
 Thread 1 with return value       Ticket sheet 4
main Thread return value: 5
 Thread 2 with return value       Ticket sheet 2
 Thread 2 with return value       Ticket sheet 3
 Thread 2 with return value       Ticket sheet 4
main Thread return value: 5

Topics: Java Multithreading