Multithreaded Execution Order

Posted by Dan_Mason on Sun, 06 Mar 2022 18:10:17 +0100

Sample code:

public class App {

    static Thread thread1 = new Thread(() -> System.out.println("thread1"));

    static Thread thread2 = new Thread(() -> System.out.println("thread2"));

    static Thread thread3 = new Thread(() -> System.out.println("thread3"));

    public static void main(String[] args) {

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

One of the results of multiple executions:

 

Multiple Execution Result Two:

 

Threads do not execute immediately after they are started. Instead, it waits for a CPU resource to be scheduled, and the order of the CPU scheduling is computed using complex algorithms. Wait until the starting thread gets CPU instructions before making a switch with the main thread to execute the run method. This causes the results to be random every time we execute them.

Description:
Threads include the following five states.
1. New state: When a thread object is created, it enters a new state. For example, Thread thread = new Thread().
2. Runnable: Also known as executable state. When a thread object is created, other threads invoke the object's start() method to start the thread. For example, thread.start(). Threads in a ready state may be scheduled for execution by the CPU at any time.
3. Running state: Threads get CPU privileges to execute. It is important to note that threads can only move from ready state to running state.
4. Blocked state: Blocked state is when a thread gives up CPU usage for some reason and temporarily stops running. There is no opportunity to go to the running state until the thread is ready. There are three types of blocking:
(01) Wait for blocking -- Allows a thread to wait for a job to complete by calling the thread's wait() method.
(02) Synchronization Blockage - Threads fail to acquire synchronized synchronized synchronization locks (because locks are occupied by other threads), which enter a synchronization blocking state.
(03) Other blockages -- threads enter a blocking state by calling their sleep() or join() or making I/O requests. When the sleep() state times out, join() waits for the thread to terminate or time out, or I/O processing completes, the thread reverts to a ready state.
5. Dead state: When a thread has finished executing or exited the run() method because of an exception, the thread ends its life cycle.

Method one: Join() uses:

public class AppJoin {

    static Thread thread1 = new Thread(() -> System.out.println("thread1"));

    static Thread thread2 = new Thread(() -> System.out.println("thread2"));

    static Thread thread3 = new Thread(() -> System.out.println("thread3"));

    public static void main(String[] args) throws InterruptedException {

        thread1.start();
        thread1.join();

        thread2.start();
        thread2.join();

        thread3.start();

    }
}

Execution results:

The result is the same no matter how many times you execute it.

Principle analysis:
Join() function: Let the main thread wait for the child thread to finish running before continuing.
This code means this:

When the program calls the join method of the thread1 thread in the main thread, the main thread discards cpu control and returns the thread1 thread to continue execution until the thread thread1 finishes execution
So the result is that thread1 thread executes before it reaches the main thread, which is equivalent to synchronizing thread1 threads in the main thread. When thread1 executes, the main thread has the opportunity to execute

jion method source code:

Source Interpretation:
The isAlive() method determines if the current thread is active. An active state is when a thread is started and not terminated, such as running or ready to start running.

So from a code point of view, if the thread is generated but not started, the join() method that calls it is useless and will continue executing directly down.
In Object. In java, wait() is used to put the current thread into a waiting state, and it also lets the current thread release the locks it holds.

Code Step Interpretation:
1: The main thread runs;
2: Create thread1 thread (the thread1 thread state after creation is new);
3: The main thread calls thread1.start() method (thread1 thread state becomes ready, waiting for a resource scheduling from the cpu, thread1 state becomes running when resources are available);
4: The main thread calls thread1.join() method (the main thread hibernates and waits for the child thread thread1 to finish running).

Method 2: Use of ExecutorService ():

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AppExecutorService {
    static Thread thread1 = new Thread(() -> System.out.println("thread1"));


    static Thread thread2 = new Thread(() -> System.out.println("thread2"));

    static Thread thread3 = new Thread(() -> System.out.println("thread3"));

    static ExecutorService executorService = Executors.newSingleThreadExecutor();

    public static void main(String[] args) {

        executorService.submit(thread1);
        executorService.submit(thread2);
        executorService.submit(thread3);

        executorService.shutdown();
    }
}

Execution results:

The result is the same no matter how many times you execute it.

Principle: Using the newSingleThreadExecutor of Excutors in a concurrent package produces a single-threaded thread pool whose underlying principle is a FIFO queue. Executor in code. Subit adds 123 threads in turn, which guarantees the order of execution according to FIFO's characteristics, i.e. 123 execution results.

Topics: Java