编程知识 cdmana.com

Java Foundation Series: multithreading Foundation

Come on friends , Let's get to know .

Worldly vagrant : Technology focused procedural apes

Let's talk about it in this section Java Multithreaded things in

I'll figure it out : What you must ask in an interview ,:slightly_smiling_face:

well , Now before we talk , Let's take a look at the basic concepts of multithreading

Basic concepts

process

Let's talk about what is Program

  • A program is a collection of instructions , It's not about programming languages
  • stay CPU level , The program written by the programming language will eventually be compiled into the corresponding instruction set for execution

To put it more generally , Any kind of software we use can be called degree , such as :

  • QQ, WeChat , Thunderbolt, etc

The basic unit that the operating system uses to allocate system resources is called process , Multiple processes can exist in the same program

windows If the system, you can view the executing process through the task manager :

 The task manager looks at the process

process It's a static concept , During process execution , Will take up a specific address space , such as :CPU, Memory , Disks, etc . so to speak process It is the smallest unit of application system resources, and all of them exist independently

And one thing we should pay attention to is :

  • In unit time , A process is executed in a single processor ,CPU The processor can only process one process at a time . It's just CPU The switching speed is very fast

Now? CPU said 4 nucleus 8 Threads 、6 nucleus 12 Thread is to improve the execution ability of the computer

So there's a problem involved : Context switch

When the operating system decides to transfer control from the current process to a new process , It's context switching , Save the context of the current process 、 Recover the context of the new process , Then pass control to the new process . The new process will start where it last stopped

Excerpt from :《 Deep understanding of computer systems 》:1.7.1 process

This is process data saving and recovery

Threads

good , There's so much talk on it , Finally, I got to the theme : Threads

I said before process It's the smallest unit to apply for resources , that Threads Is the smallest unit of execution in a process , It's a single continuous control process in the process , And there is at least one thread in the process : That's what we call The main thread

If you know Android To develop it , Then we should be able to understand this better

 The name of the least executing thread in the process

A process can have multiple parallel threads , At least one thread . Threads are independent of each other in a process , Execution between multiple threads has no impact , But if multiple threads operate on the same piece of data , So it's bound to have an impact ( This is the thread safety problem we mentioned earlier )

Typical cases : Selling tickets

Threads in a process share the same memory unit ( Memory address space ), Including access to the same variables and objects , Objects can be allocated from the same heap , Can do communication , Data exchange 、 The operation of data synchronization

And share in the process CPU resources , In other words, the thread execution order preempts the process CPU resources , Whoever can seize it can execute it .

I'll talk about the thread status later

There's another one called : fibers / coroutines ( The same concept )

Lighter level threads , Running inside the thread , It's a user space level thread . Talk later

Interview frequency : The difference between process and thread

  1. The fundamental difference : Process is the basic unit used by the operating system to allocate resources , The thread is the smallest unit of execution scheduling
  2. The execution of a thread depends on the process , And threads share resources in the process

  3. Each process has its own resource space ,CPU In the process switching, the cost is high , And the cost of threads is smaller

Realization way

After understanding the basic concepts , It is necessary to enter the specific practical operation link , stay Java in , If you want to create multithreading , There are a total of 5 In the way , remember : It's a form of expression .

Let's look at two of them first

Inherit Thread Realization

stay Thread Source code , Contains the Java Introduction of thread in , How to create two representations of a thread , This includes how to start the created thread :

Thread Introduction information in

So , The annotation document of a class is very important

So let's create a thread ourselves :

class CusThread1 extends Thread {

    @Override
    public void run() {
        super.run();
        System.out.println(" The name of the currently executing thread :" + Thread.currentThread().getName());
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
        System.out.println(" Current execution thread name :" + Thread.currentThread().getName());

        CusThread1 cusThread1 = new CusThread1();
        cusThread1.start();
    }
}

This is one of the simplest thread creation , Let's see if it's a success

Thread The first program execution result

So there are two steps to create a thread :

  • Define a class , Inherit Thread The main class and override run()
  • call start() Method start execution

Here's one thing to note , If we want to start a thread , Must be a call start() Method , Instead of calling run(), There is a difference between the two :

  • call start() The method is Java virtual machine Will call the run() Method , Two threads will be created here :
    • Current thread ( Return from call to start Method )
    • perform run() The thread of
public synchronized void start() {
    /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
        }
    }
}

//  Here is start() Method to start execution 
private native void start0();
  • And if you call run() Method words , It's equivalent to calling ordinary methods , No new threads will be created , Here we need to focus on

It's a way , But we don't recommend it :

  • Java It's a single inheritance , If by inheritance Thread, If this class needs to inherit other classes , There is no way
  • Thread You need to start new The current object , If there is a shared property in this class , That means that every time a new object is created, it will have this property in the heap space of the new object , So every time we operate the attribute, we actually operate the property in the current object heap space

It can be a little difficult to understand , Let's do an experiment

public class ThreadDemo1 {

    public static void main(String[] args) {
        System.out.println(" Current execution thread name :" + Thread.currentThread().getName());

        CusThread1 cusThread1 = new CusThread1();
        CusThread1 cusThread2 = new CusThread1();
        CusThread1 cusThread3 = new CusThread1();
        cusThread1.start();
        cusThread2.start();
        cusThread3.start();
    }
}

class CusThread1 extends Thread {

    public int i = 1;

    @Override
    public void run() {
        for (int j = 0; j < 5; j++) {
            System.out.printf(" Current thread :%s, i=%s \n", Thread.currentThread().getName(), i++);
        }
    }
}

Thread Shared variables

Of course , There are also such problems to be solved :

  • That is to set the shared variable to static, Let's see the effect

Thread Shared variables

Realization Runnable Interface

Let's take a look at this approach ,Runnable It's an interface , It only contains run() Method , We can create multithreads by rewriting its interface method

The specific implementation is as follows

class CusThread2 implements Runnable {
    public int i = 1;

    @Override
    public void run() {
        for (int j = 0; j < 5; j++) {
            System.out.printf(" Current thread :%s, i=%s \n", Thread.currentThread().getName(), i++);
        }
    }
}

CusThread2 thread = new CusThread2();

new Thread(thread).start();
new Thread(thread).start();
new Thread(thread).start();

There are two steps to creating a thread and starting it :

  • Thread class implementation Runnable Interface , And rewrite run() Method
  • adopt new Thread(Runnable) To create a thread and call start() start-up

This is recommended here , because :

  • Java Although it's a single inheritance , But it's a way to achieve more , adopt Runnable This way of interface does not affect the inheritance of thread class , You can also implement multiple interfaces
  • It's about sharing variables , See above , Shared variables in thread classes are not defined static, But there will be no Thread The problem in the way

Runnable Shared variables

Because when you create a thread , Thread classes are created only once , It's all started through Thread Class , So there's no problem with that

Expand : The proxy pattern

This leads to a pattern called : The proxy pattern . What is The proxy pattern Well ?

  • That is to provide a proxy object for other objects , Access to this object is controlled by proxy objects

Like the one above Runnable/Thread, The actual business logic is written in Runnable Interface , But we do it through Thread To control their behavior, such as :start, stop etc.

The proxy pattern The key point is :

  • Take advantage of Java One of the characteristics of polymorphism , Determine the proxy class and the surrogate class
  • Both the proxy class and the proxy class need to implement the same interface

Here is a book about design patterns :《 Zen of design pattern 》

Let's take a case , Learn more about multithreading

Multi window ticket selling case

Let's use two ways to create threads to do the ticketing example :

public class TicketThreadDemo {

    public static void main(String[] args) {

//        startTicketThread();
        startTicketRunnable();

    }

    private static void startTicketRunnable() {
        TicketRunnable ticketRunnable = new TicketRunnable();

        List<Thread> ticketThreads = new ArrayList<Thread>(5) {{
            for (int i = 0; i < 5; i++) {
                add(new Thread(ticketRunnable));
            }
        }};

        ticketThreads.forEach(Thread::start);
    }

    private static void startTicketThread() {
        List<TicketThread> ticketThreads = new ArrayList<TicketThread>(5) {{
            for (int i = 0; i < 5; i++) {
                add(new TicketThread());
            }
        }};

        ticketThreads.forEach(TicketThread::start);
    }
}

// Runnable The way 
class TicketRunnable implements Runnable {

    private int ticketCount = 10;

    @Override
    public void run() {
        while (ticketCount > 0) {
            System.out.printf(" window :%s,  Selling tickets :%s \n", Thread.currentThread().getName(), ticketCount--);
        }
    }
}

// Thread The way 
class TicketThread extends Thread {

    //  remember , Shared variables must be used here static,
    private static int ticketCount = 10;

    @Override
    public void run() {
        while (ticketCount > 0) {
            System.out.printf(" window :%s,  Selling tickets :%s \n", Thread.currentThread().getName(), ticketCount--);
        }
    }
}

Wrote together , It won't be split , You can try it yourself

TicketDemo

Commonly used API Properties and methods

Here we will introduce some methods commonly used in multithreading , We've used the above :

  • start()

This method has also been introduced , It's just more than that , Let's look at other ways

sleep()

According to the precision and accuracy of the system timer and scheduling program , Put the currently executing thread into sleep state ( To suspend execution ) To the specified number of milliseconds . This thread will not lose ownership of any monitors

A little introduction , Is to sleep the program at a specified time , After sleeping time , Will continue to carry out , This is a static method , Just call it directly .

One thing to pay attention to : The unit of sleep time is millisecond

//  Convenient time string method , Self encapsulated , Ignore 
System.out.println(LocalDateUtils.nowTimeStr());
try {
    //  sleep 2s
    Thread.sleep(2000L);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println(LocalDateUtils.nowTimeStr());

sleep

isAlive()

Verify that the current thread is active , Activities are true, Otherwise false

private static void alive() {
    //  Last example , I'll use it 
    TicketThread ticketThread = new TicketThread();
    System.out.println(ticketThread.isAlive()); // false
    ticketThread.start();
    System.out.println(ticketThread.isAlive()); // true
}

join()

As we know above, threads are preempted CPU Resources to perform , Then the execution of threads must be unpredictable , But by join() Method , Will block other threads , After the current thread is executed , Continue to execute other threads

public static class JoinThread extends Thread{
    private int i = 5;

    public JoinThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (i > 0) {
            System.out.println(" Current thread 【" + this.getName() + "】,  Execution value 【" + i-- + "】");
        }
    }
}

private static void join() {
    JoinThread t1 = new JoinThread("T1");
    JoinThread t2 = new JoinThread("T2");

    //  By default 
    t1.start();
    t2.start();

    //  Added join After the 
    t1.start();
    t1.join();

    t2.start();
    t2.join();
}

join

yield

The current thread is willing to give up the current use of the processor , In other words, the currently running thread will give up CPU From running state to ready state , And then let CPU Determine which thread is running , If no other thread executes , Then the current thread will execute immediately

The current thread will enter the ready state , wait for CPU The seizing of resources

Most of the time, it's used when two threads execute alternately

stop

stop() Well understood. , Force the current thread to stop , However, the current method has been stopped by violence JDK Marked as obsolete , Another approach is recommended :interrupt()

Interrupt this thread

Multithreaded state

Threads are mainly divided into 5 States :

  • Freshman state

That is to say, the thread is in the newly created state , Nothing has been done

TicketThread ticketThread = new TicketThread();
  • Ready state

When the created thread calls start() Method to enter the ready state , Here we have to pay attention to ,start() It doesn't have to start running after that , Instead, the thread is added to the queue , And then they started to grab CPU resources , Whoever can seize it will start to execute

ticketThread.start();
  • Running state

The thread entering the ready state preempts CPU After the resource, start executing , This is the state of execution .

In the process, the business logic begins to execute

  • Blocked state

When the program is running , When some abnormal information occurs, the program cannot continue to run normally , It's going to be blocked

When the cause of blocking is eliminated , The thread will return to the ready state , Grab at random CPU The resource then waits for execution

Methods that cause threads to block :

  1. sleep()
  2. join()
  • Death state

When the normal operation of the program business logic is completed or the program ends due to some circumstances , This will lead to death

The way to get into a state of death :

  1. The program is running normally
  2. Throwing an exception causes the program to end
  3. Artificial interruption

Thread state

summary

Most of the concepts are in this article , There's very little code , You need to understand

Let's just write here , And thread synchronization , The contents of the thread pool , Let's move on to

版权声明
本文为[osc_ m53xdida]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201225120653050g.html

Scroll to Top