JavaSE multithreading mechanism

Introduction to Threads

1. Concepts of Programs, Processes, Threads

  • Program: An ordered collection of instructions and data, which has no running meaning in itself, is a static concept.
  • Process: An execution process of a program is a dynamic concept. A process is a unit of system resource allocation.
  • Threads: Usually a process can contain several threads, of course, at least one thread in a process, otherwise it has no meaning. Threads are the units of CPU scheduling and execution.

2. Love and hate between processes and threads
Processes have many advantages, they provide multiprogramming, make us feel that each of us has our own CPU and other resources, and can improve the utilization of the computer. Many people don't understand why threads are needed since processes are so good. In fact, a close look will reveal that there are still many defects in the process, mainly reflected in two points:

  • A process can only do one thing at a time. If you want to do two or more things at the same time, a process cannot do anything.
  • If a process is blocked during execution, such as waiting for input, the entire process hangs, and even if some of the work in the process is not dependent on the input data, it cannot be executed.

If these two shortcomings are difficult to understand, take a real-world example to illustrate: if we view the process of our lessons as a process, what we need to do is listen to the teacher's lectures in our ears, take notes in our hands, and think about the problem in our mind, so that we can effectively complete the task of listening. If only the mechanism of process is provided, the above three things will not be executed at the same time, only one thing can be done at the same time, and you cannot take notes or think with your brain while listening. If the teacher writes an arithmetic on the blackboard and we start taking notes, and suddenly the teacher can't push it any further and gets stuck. He's thinking there, and we can't do anything else, even if you want to think about a problem you didn't understand just now. That's the second one.

Now you should understand the drawbacks of the process. The solution is very simple. We can let three independent processes, listening, writing and thinking, run side by side, which can obviously improve the efficiency of listening. Threads, a similar mechanism, are also introduced in real-world operating systems.

3. Core concepts

  • Threads are separate execution paths
  • When a program is running, there will be multiple threads in the background, such as the main thread and the gc thread, even if you do not create a thread yourself.
  • main() is called the main thread and is the entrance to the system to execute the entire program.
  • In a process, if multiple threads are opened up and the running of threads is scheduled by the scheduler, which is closely related to the operating system and cannot be interfered with artificially.
  • When operating on the same resource, there will be the problem of resource seizure, which requires concurrency control.
  • Threads incur additional overhead, such as CPU scheduling time and concurrency control overhead
  • Each thread interacts in its own working memory, and improper memory control can result in inconsistent data

Thread implementation

1. Creation method 1
Inherit Thread Class

  • Declare a class as a subclass of Thread
  • Override run() method of subclass
  • Then open the thread in the main () method through the thread's start () method

explain

  • Each user acts as a process on the computer, so there are two processes, each with four threads.

    Example
public class TempTest{
    public static void main(String[] args){
        Thread_one thread_one = new Thread_one();
        Thread_two thread_two = new Thread_two();
        thread_one.start();
        thread_two.start();
    }
}

public class Thread_one extends Thread{
     @Override
    public void run(){
         for(int i=0;i<2000;i++){
             System.out.println("I'm programming");
         }
     }
}

public class Thread_two extends Thread{
    @Override
    public void run(){
        for(int i=0;i<2000;i++){
            System.out.println("I was playing games");
        }
    }
}

Run result: (intercepted part)

2. Creation Mode 2: Implement Runnable Interface

  • Implement Runnable Interface
  • Override run method in Runnable implementation class
  • Create a Runnable implementation class object A, and A creates a Thread object as a parameter
  • Start threads through the start () method
public class TempTest{
    public static void main(String[] args){
        Thread_two two = new Thread_two();
        Thread thread1 = new Thread(two);

        Thread_one one = new Thread_one();
        Thread thread2 = new Thread(one);

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

    }
}

public class Thread_one implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<2000;i++){
            System.out.println("I was playing games");
        }
    }
}

public class Thread_two implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<2000;i++){
            System.out.println("I'm programming");
        }
    }
}

Run result (only part of screenshot)

3. Creation method 3: Implement Callable interface
(For understanding only, learn again when you use it: Episode 8 of Mad Multithreaded)

Thread state


Thead.State

  • NEW
  • RUNNABLE
  • BLOCKED
  • WAITING
  • TIMED_WAITING
  • TERMINATED
public class TestLamda {

    public static void main(String[] args) throws InterruptedException {
        ThreadOne thread = new ThreadOne();

        Thread.State state = thread.getState();     //NEW
        System.out.println(state);

        thread.start();
        state = thread.getState();          //Run
        System.out.println(state);

        while(state!= Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);

        }

    }
}

class ThreadOne extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

Thread Concurrency Initial Recognition

Example

public class Demo implements Runnable{

    private int ticketNumbers = 10;

    public static void main(String[] args){
        Demo demo = new Demo();
        Thread t1 = new Thread(demo,"Student");
        Thread t2 = new Thread(demo,"Teacher");
        Thread t3 = new Thread(demo,"Cattle");
        Thread t4 = new Thread(demo,"Parent");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }

    @Override
    public void run(){
        while(true) {
            if(ticketNumbers <= 0) break;
            System.out.println(Thread.currentThread().getName() + "-->Get the first" + ticketNumbers-- + "ticket");

        }
    }
}

Run Results

discover problems
The thread is randomly scheduled before it has finished executing, making it uncontrollable.

Thread method

  • setPriority (int newPriority) changes the priority of threads, threads with higher priority are more likely to get CPU
//Priority Minimum 1, Maximum 10
t1.start();
t1.setPriority(1);

t2.start();
t2.setPriority(10);
  • static void sleep (long millis) sleeps the currently executing thread for a specified number of milliseconds
  • void join() queues and waits for the thread to terminate
public class Thread_one implements Runnable{
    boolean flag = true;

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("I was playing games");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread_one  one = new Thread_one();
        Thread t1 = new Thread(one);
        t1.start();
        for(int i = 0; i<500; i++){
            if(i==100) t1.join();
            System.out.println("main"+i);
        }
    }
}
  • static void yield() pauses the currently executing thread object and executes other threads
public class Demo {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        Thread t1 = new Thread(myYield,"a");
        Thread t2 = new Thread(myYield,"b");
        t1.start();
        t2.start();
    }
}

class MyYield implements Runnable{
    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName()+"Thread Starts Execution");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"Thread End Execution");
    }
}

//Run Results
a Thread Starts Execution
b Thread Starts Execution
a Thread End Execution
b Thread End Execution
  • void interrupt () interrupts threads, not recommended
  • boolean isAlive() tests whether the thread is active

Thread Stop

1. Rules

  • Suggest that the thread stop normally
  • Recommended use of flags
  • Do not stop the thread using methods such as stop or destroy provided by JDK
public class Thread_one implements Runnable{
    boolean flag = true;

    @Override
    public void run(){
        while(flag){
            System.out.println("I was playing games");
        }
    }

//Set Flag Bits
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {
        Thread_one  one = new Thread_one();
        Thread t1 = new Thread(one);
        t1.start();
        for(int i = 0; i<3000; i++){
            System.out.println("main"+i);
            if(i == 900) one.stop();
        }
    }
}

Thread Synchronization

1. Queues

  • Multiple threads operate on the same resource
  • Thread synchronization is a wait mechanism in which multiple waiting pools that need to access this object at the same time form a queue, waiting for the previous thread to finish using it and the next thread to use it again.

2. Locks

  • When an object is locked, all operations of that object are merged into one atomic operation.

3. Thread synchronization

  • Thread Synchronization = Queue + Lock
  • Since multiple threads of the same process share the same block of storage space, this brings convenience and access conflicts. To ensure data is accessed correctly in the method, a synchronized lock mechanism is added when accessing. When a thread acquires an exclusive lock on an object, it is exclusive to the resource, and other threads must wait until the lock is released after use.
  • A thread holding a lock causes all other threads that need it to hang.
  • Under multithreaded competition, unlocking and releasing locks can result in more context switching and scheduling delays, causing performance problems.

4. Unsafe Cases
There are two tickets in the station. Now three people come in at the same time to buy tickets.
A: Show that there are 2 tickets left, buy the tickets, minus 1
B: Show that there is 1 ticket left, buy the ticket, minus 1
C: Display that there are 0 tickets left, see no tickets, do not buy tickets
But is that really the case?

Threads are known to execute concurrently on computers and thread scheduling is random. Suppose there is a case where:
A: Show that there are 2 tickets left, buy the ticket
B: Show that there are 2 tickets left, buy the ticket, minus 1
C: Show that there is 1 ticket left, buy the ticket, minus 1
A: Votes minus 1
The result number of votes eventually changed to -1 because the operation of thread A was interrupted because it did not complete completely.

5. Synchronization mechanism implementation

  1. synchronized method
  • public synchronized void method(int args){}
  • The synchronized method controls access to "objects". Each object corresponds to a lock, and each synchronized method must acquire a lock on the object calling the method to execute. Otherwise, the thread will block. Once the method executes, the lock will be exclusive until the method returns, and then the blocked thread can acquire the lock and continue execution.
  • Disadvantage 1: Too much method can affect efficiency
  • Disadvantage 2: Locks are required only for content that needs to be modified within a method
  • Disadvantage 3: Too many locks change thread parallelism to serialization
  • Note: Multiple threads operating on the same resource triggered a synchronization mechanism, so we want to lock the same resource.
public class Demo {
    
    private static int a=1000;
    public static void main(String[] args) {
        Thread_three th = new Thread_three();
        
        new Thread(th,"t1").start();
        new Thread(th,"t2").start();
        new Thread(th,"t3").start();
    }
}

class Thread_three implements Runnable{
    
    private static int ticket = 10;				//Three objects operate on the same resource
    private static boolean flag = true;
    @Override
    public void run(){
        while(flag == true){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void buy() throws InterruptedException {			//Keyword synchronized implements synchronization mechanism
        if(ticket <= 0){
            flag = false;
            return;
        }
        
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName()+"Get it"+ticket--);
    }
}

Running results conform to synchronization mechanism

  1. synchronized block
  • synchronized(Obj){}
  • Obj calls it a synchronization monitor and can be any object, but it's recommended to use shared resources as a synchronization monitor
public class Demo28_SafeBank {
    public static void main(String[] args) {
        Account1 account = new Account1(100, "Marriage Fund");
        Drawing1 you = new Drawing1(account, 50, "Exhibition Hall");
        Drawing1 girlfriend = new Drawing1(account, 100, "sad");
        you.start();
        girlfriend.start();
    }
}

//account
class Account1 {
    int money;//balance
    String cardName;//Card Name

    public Account1(int money, String cardName) {
        this.money = money;
        this.cardName = cardName;
    }
}

//Bank: Simulated withdrawal
class Drawing1 extends Thread {
    Account1 account;//account
    int drawingMoney;//Draw amount
    int nowMoney;//Money in your hand

    public Drawing1(Account1 account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    //Draw money
    @Override
    public void run() {
        //The object of a lock is the amount of variables, and the objects to be inspected need to be added or deleted.
        synchronized (account) {
            //Determine whether you have money
            if (account.money - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "Sorry, your credit is running low,Money cannot be withdrawn");
                return;
            }
            try {
                Thread.sleep(1000);//Enlarge the occurrence of the problem
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Card Amount = Balance - Your Money
            account.money = account.money - drawingMoney;
            //Money in your hand
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.cardName + "The balance is:" + account.money);
            //this.getName()==Thread.currentThread().getName()
            System.out.println(this.getName() + "Money in Hand:" + nowMoney);
        }
    }
}

3. Lock

//Test Lock Lock
public class Demo32_ThreadLock {
    public static void main(String[] args) {
        TestLock testLock = new TestLock();
        new Thread(testLock).start();
        new Thread(testLock).start();
        new Thread(testLock).start();
    }
}

class TestLock implements Runnable {
    int tickerNums = 10;
    //Define Lock Lock
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            //Locking
            try {
                lock.lock();
                if (tickerNums <= 0) {
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(tickerNums--);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //Unlock
                lock.unlock();
            }
        }
    }
}

The three methods listed above take precedence: Lock > Synchronization Code Block > Synchronization Method

Thread Communication Problem

  • Pipeline method
  • Semaphore method

Thread Pool

1. Understanding

  • Background: Constantly creating and destroying, using very large resources can have a significant impact on Performance
  • Thought: Create many threads in advance, put them into the thread pool, get them directly when using them, put them back into the pool after using them, you can avoid frequent creation and destruction, so as to achieve reuse
  • Benefits: increased response speed, reduced resource consumption, easy thread management

2. Use
ExecutorService: A true thread pool interface. Common Subclass ThreadPoolExecutor

  • void execute (Runnable command): Execute task/command
  • submit(): Perform tasks
  • void shutdown (): Close connection pool

Executor: Tool class, factory class for thread pools, used to create and return different types of thread pools

//Test Thread Pool
public class Demo35_ThreadPool {
    public static void main(String[] args) {
        // 1. Create a service to wipe the interline thread pool
        // NewFixedThreadPool (Thread Pool Size)
        ExecutorService service = Executors.newFixedThreadPool(10);
        //implement
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //Close Connection
        service.shutdown();
    }
}

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

Keywords: Java

Added by Nukeum66 on Thu, 20 Jan 2022 19:50:01 +0200