Many students face multithreading problems are very big, because it is difficult to use their own projects, but every high salary job interview will be asked. After all, large factories are now using multi-threaded high concurrency, so this piece of content is not clearly not.

Today this article, as the foundation of multithreading, will first talk about the following issues:

  1. Why multithreading?
  2. Program vs process vs thread
  3. 4 ways to create a thread?

Why multithreading

Every technology comes along to solve an existing problem.

Before the Internet was mostly stand-alone services, small volume; Now it’s more of a cluster service, with multiple users accessing the server at the same time, so there are many threads accessing the server concurrently.

For example, in the e-commerce system, a large number of users access the server at the same time, such as during the hour shopping, so the development of the company is basically multithreaded.

The use of multiple threads does improve the efficiency of the operation, but at the same time, we need to pay special attention to the addition and deletion of data, which is a thread safety issue, such as HashMap vs HashTable, Vector vs ArrayList.

There are many ways to be thread safe, such as locking, but there are other problems that can occur such as deadlocks, so multithreaded issues can be a bit of a hassle.

Therefore, we need to understand how multithreading works and the problems it can cause and how to solve them in order to land a high-paying job.

Process vs. Thread

Application program

When it comes to process, you have to start with program.

A program is simply code, or a collection of instructions. For example, “wechat. Exe” this is a program, this file is finally to get the CPU inside to execute.

Process the process

When a program is running, it is a process.

So programs are “dead” and processes are “alive”.

In task Manager, for example, there are processes, which are “moving” applications.


Q: Are these processes executed in parallel?

A single-core CPU can execute only one process in a time slice. But because it switches so quickly, we don’t feel it, creating the illusion of multiple processes. (Multicore cpus really do run in parallel.)

Q: What if the process doesn’t finish?

When process A finishes executing A time slice but has not finished executing it, the data information that has just been executed is saved to facilitate the next execution, which is called “save scene”.

Then wait for the next time you grab the resources to execute, first “restore the scene”, and then continue to execute.

And so on.

All this saving and restoring is expensive and slows down the program.

Q: Is there a more efficient way?

If two threads belong to the same process, there is no need to save and restore the scene.

So that’s the idea of the NIO model, and that’s why the NIO model is much more efficient than the BIO model, and we’ll talk about that later.

Thread the thread

Threads, which are specific execution paths in a process, do the real work.

Only one thread can execute a timeslice in a process, but because the timeslice can be switched so quickly, it seems to be happening at the same time.

There is at least one thread in a process. For example, the main thread, which is the main() function we usually write, is the user thread; There are also GC threads produced by the JVM, which are responsible for garbage collection and are daemon threads.


Each thread has its own stack, which records the relationship between methods called by each other in the thread.

But all threads in a process share the heap.

Therefore, different processes cannot access each other’s memory. Each process has its own memeory space, which is also called virtual memory.

With this virtual memory, each process feels like it owns the entire memory space.

The mechanism of virtual memory is to mask the limitations of physical memory.

Q: What if physical memory is used up?

Using a hard disk, such as a Windows paging file, is to store a portion of your virtual memory on the hard disk.

Correspondingly, programs run very slowly at this point, because hard disk reads and writes much more slowly than memory, which is the perceived slowness, which is why the computer freezes when you open too many programs.

Q: How big is this virtual memory?

For 64-bit operating systems, each program can use 64 bits, which is about 2^64!

If you are not clear about binary related content, the public number inside reply “binary” to obtain the corresponding article oh ~

conclusion

To summarize, a CPU can only execute one process in a timeslice.

After the CPU allocates resources to a process, the process starts running. The thread in the process to seize resources, a time slice only one thread can execute, the first to grab it is the one.


Multi-process vs. multi-thread

Each process is independent. If process A fails, process B will not be affected.

Even though threads run independently, threads in a process share the same heap, and if a thread runs out of memory, all threads in that process die.

Therefore, multiple processes can improve the fault tolerance of the systemfault toleranceAnd the biggest advantage of multi-threading is the communication between threads is very convenient.

Communication between processes requires additional mechanisms, such as interprocess communication-IPC, or network transmission, etc.

How to create a thread

This is a bunch of concepts, but let’s look at the implementation.

Java is through the java.lang.Thread class to achieve multithreading functionality, so let’s take a look at this class.

As you can see from the documentation, Thread directly inherits from Object and implements the Runnable interface.

There are also two ways to create threads in the official documentation:

One way is to inherit the Thread class and override the run() method, which contains the code to be executed by the Thread.

The thread is started by calling the start() method on an instance of the new class.


The second is to implement the Runnable interface and implement the run() method. The run() method also writes the code to be executed by the thread.

A slight difference is that to start a thread, you need to create a new thread, pass in an instance of the class you just created that implements the Runnable interface, and call start(), which is actually proxy mode.


If you have any other questions, you can say:

  1. Callable interface;

  2. Start a thread through a thread pool.

However, using a thread pool to start a thread is also created in one of the first two ways.

These two methods are not discussed here, but let’s look at the first two methods in detail.

Thread class inheritance

public class MyThread extends Thread {

    @Override

    public void run(a) {

        for (int i = 0; i < 100; i++) {

            System.out.println("Qi 666:" + i);

        }

    }

    public static void main(String[] args) {

        MyThread myThread = new MyThread();

        myThread.start();

        for (int i = 0; i < 100; i++) {

            System.out.println("Main thread" + i + ": Sister Qi 666");

        }

    }

}

Copy the code

Here,

  • The main function is the main thread, which is the entrance to the program and executes the entire program.

  • The program began to execute after the first start a new thread myThread, in this thread output “xiaoqi”;

  • The main thread executes in parallel and prints “main thread I: Sister Qi”.


Look at the result, it is two threads alternately praise me ~


Q: Why are the results different from mine?

In multithreading, the result of each run may be different, because there is no way to artificially control which thread grabs the resource first and at what time.

Of course, we can give a thread priority, but a high priority does not guarantee that the thread will be executed first, only that there is a higher probability that the resource will be executed first.

Implement the Runnable interface

It’s used more often.

public class MyRunnable implements Runnable {

    @Override

    public void run(a) {

        for(int i = 0; i < 100; i++) {

            System.out.println("Qi 666:" + i);

        }

    }



    public static void main(String[] args) {

        new Thread(new MyRunnable()).start();



        for(int i = 0; i < 100; i++) {

            System.out.println("Main thread" + i + ": Sister Qi 666");

        }

    }

}

Copy the code

The results were similar:


As mentioned earlier, the thread starts a little differently here, because the new class only implements the Runnable interface, so we need another thread to “proxy” it, so we need to pass in an instance of our new class to a thread, which is actually proxy mode. More on this design pattern later.

summary

Which of these two ways is better?

The Runnable interface is better, mainly because of Java single inheritance.

Note also that the thread is started with start() instead of run().

Calling run() is just a call to the method, a normal method call; Start () is the thread that starts, and the JVM calls run() for that thread.

Well, the above is all the content of the first multithreading, here is mainly to help you review the basic concept, and no contact with small partners can enter. If you want to read more about multithreading, give me a thumbs up and leave a comment

I am Xiao Qi, lifelong learner, every night at 9 o ‘clock, we will be there or be square in the study room ❤️