Initial multithreading of Java EE 01

Write in front

We have learned the basic knowledge of the process and know that a process needs to apply for resources from memory to run. These are the basis for us to learn today's knowledge.

thread

The process needs to apply for resources to run and release resources to end. Once down, the operating system is acceptable. But if it's too many times, I don't think anyone can afford it. Therefore, intelligent human beings have proposed a concept called Thread. The so-called Thread has the same function as the process. Sometimes we also call it "lightweight process". However, it has the following advantages.

  • A thread does not need to open up and release resources. It exists in a process and shares this resource with this process.
  • A process can contain one or more threads.

In Linux, our process is also represented by PCB. We find that the last pid in the figure below is the same as the first pid and belongs to the same process. It can be considered that these two threads occupy the same space. Note that the operating system does not recognize processes and threads, but only PCBs. Creating a process / thread is creating a PCB. We can also think of a process as a thread.

Thread and process relationship

This is a classic interview question. We must know it.

  • A process can contain one or more threads
  • Each process has an independent memory space (virtual address space), which is shared by the threads contained in the process
  • Process is the basic unit of space allocated by the operating system, and thread is the basic unit of scheduling and execution of the operating system.

Threads and processes share the same piece of resources, including the following aspects

  1. Memory (variable)
  2. File (later)

Relationship between thread and code

A thread is the execution flow of a code, which we won't understand first.

Multiprocess and multithreading

As we said earlier, the development and destruction of threads do not require the participation of space, so threads are better than processes to a certain extent. We want the computer to execute as fast as possible, so there are two ways. Let's take an example. Suppose there are 100 here 🦃, Our goal is to eat these 100 🦃. How can we improve the speed of eating chicken?

  1. Multi process
  2. Multithreading

Multi process

We let two funny old fellow iron come to eat chicken separately, give each old fellow iron a house, 50 persons per person. 🦃, Here is to eat more chicken. We have two sets of tables, two rooms, that is, two resources have been opened up, and two old fellow iron can not see each other how much they ate, which is the process is isolated.

Multithreading

Multithread is a bit of a waste of resources. Can we let two funny old fellow eat chicken in the same room? This is multithreading.

We just created a funny old fellow and did not open up new resources.

Too many threads

We hope that the faster the better, but if the thread speed is too much, there will be some problems.

  • Too many threads, frequent scheduling and too much overhead
  • Thread unsafe
  • If one thread in a process has an exception and the operating system does not see it, other threads may also have an exception

Too many threads, frequent scheduling, and too much overhead can lead to the squeeze of the old fellow.

The safety may be reduced. Two old fellow iron may have seen the same chicken thigh, they may fight.

A thread in a process is abnormal and it doesn't see it. Other threads may also be abnormal. Some old fellow iron may be unhappy, it can't grab the table and lift the table.

Code demonstration

Having said so many theories, we need to practice through code. Here I use Java. In Java, we can use the object of Thread class to represent the object of the operating system. If PCB is the way the operating system describes threads, Thread is the way the code describes threads

Create a thread

We create a process in the following ways.

//Thread is a class in the standard library
// In common methods, we inherit this class,
//Override run method
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello bit");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}

Compare thread start(); And thread run();

We may feel confused. I used thread before run(); You can also get the above results. Why use thread start(); And?, What's the difference?

  • thread.start(); A thread will be created to share the same resource with the process where the main method is located
  • thread.run() did not create a new thread

You may have some doubts here, but don't be careful. Our following code may solve some of your doubts

class MyThread extends Thread {
    @Override
    public void run() {
       while (true) {
           System.out.println("hello Thread");
           try {
               Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        //thread.start();
        thread.run();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

We use thread run();

We use thread start();

Other ways to create threads

We have other ways to create threads. The essence of these creation is the same. We create a PCB through the Thread class. The difference is only the difference of Java syntax

  • A Runnable interface is used to describe a task, and the run method needs to be rewritten
  • Inherit Thread, rewrite run, use anonymous inner classes, and write Simpler Syntax, which is referred to as "syntax sugar". The readability of great people is not low
  • Inherit Runnable, override run, and use anonymous inner classes
  • Use a lambda expression to represent the task to be performed

Runnable interface

class MyThread implements Runnable{
    @Override
    public void run() {
        
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable()); //Taking an instance as a parameter is essentially the same as the first method, which tells the thread what the task is
    }
}

Inherit Thread, override run, and use anonymous inner classes

public class TestDemo {
    public static void main(String[] args) {
        //It is equivalent to creating an internal class that inherits Thread
        Thread thread = new Thread() {
            @Override
            public void run() {
               //task
            }
        };
}

Inherit Runnable, override run, and use anonymous inner classes

public class TestDemo {
    public static void main(String[] args) {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        });

    }
}

Use a lambda expression to represent the task to be performed

Lambda is essentially an anonymous function. Since methods and classes cannot be separated in Java, we make lambda an interface, which is a very simple way

public class TestDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            while (true) {
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

View Thread

Can we take a look at the threads created by ourselves? JDK is allowed. There is a jconsole in JDK that can help us. Of course, IDEA is also possible. Jconsole plays a great role. When the program we write crashes, we can check it through jconsole

class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("hello Thread");
            try {
                Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        //thread.start();
        thread.run();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Run thread run();

We can find that there are many threads, the first of which is the main thread. Other threads are built-in. We don't care

Run Thread start();, Got a Thread

Advantages of multithreading

We use multithreading to make the CPU execute faster. Let's take an example.

If we want to add 100 million times to the numbers a and B respectively, we can compare the time difference between using single thread and multithreading

public class TestDemo {
    public static long count = 1000000000;

    /**
     * serial 
     */
    public static void serial() {
        long begin = System.currentTimeMillis();
        int a = 0;
        int b = 0;
        for (int i = 0; i < count; i++) {
            a++;
        }
        for (int i = 0; i < count; i++) {
            b++;
        }
        long end = System.currentTimeMillis();
        System.out.println("serial time = " + (end - begin));

    }

    /**
     * Concurrent
     */
    public static void multiThread() {
        long begin = System.currentTimeMillis();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                int a = 0;
                for (int i = 0; i < count; i++) {
                    a++;
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                int b = 0;
                for (int i = 0; i < count; i++) {
                    b++;
                }
            }
        };
        t1.start();
        t2.start();
        try {
            t1.join();  // Thread blocking
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("multiThread() time = " + (end - begin));
    }

    public static void main(String[] args) {
        serial();
        multiThread();
    }
}

We will find that the parallel type is about half of the serial type, but it will be more than half, because the thread also takes some time to run

Recognize Thread class

We didn't know a lot about Thread just now. Now let's open the last chapter of this blog. What methods and properties are there in the Thread class. We can take a look at some of the source code in IDEA. The following is only a part. We certainly won't learn so much. It's common to learn only a part

Construction method

Thread provides many construction methods. Let's take a look

Construction methodexplain
Thread()Assign a new Thread object.
Thread(String name)Assign a new Thread object. Let's give this object a name
Thread(Runnable target)Assign a new Thread object.
Thread(Runnable target,String name)Assign a new Thread object.

Property & get method

As above, we also see common methods

attributeAcquisition methodexplain
IDgetId()ID is the identifier of a thread, and the indicator of different threads is different
namegetName()Get the name we set for the thread. If not, it is Thread-N(N is a constant)
stategetState()Auxiliary calling thread
prioritygetPriority()And the PCB in the core are not exactly the same
Whether background threadisDaemon()The created thread is not a background thread by default
Is it aliveisAlive()Whether the PCB in the core is still there
Is it interruptedisInterrupted()Determine whether the thread is interrupted

getId()

Each thread has its own ID, similar to an ID card We can check through the code

public class TestDemo4 {
    public static void main(String[] args) {
        Thread t1 = new Thread("First thread") {
            @Override
            public void run() {

            }
        };
        Thread t2= new Thread() {
            @Override
            public void run() {

            }
        };

        System.out.println(t1.getId());
        System.out.println(t2.getId());
    }
}

getName()

Why give a name to Thread? It's mainly to facilitate debugging. If there are too many Thread names, giving a name can help us quickly find the Thread we want to debug

public class TestDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread("First thread") {
            @Override
            public void run() {

            }
        };
        Thread t2= new Thread() {
            @Override
            public void run() {

            }
        };
        Thread t3= new Thread() {
            @Override
            public void run() {

            }
        };
        System.out.println(t1.getName());
        System.out.println(t2.getName());
        System.out.println(t3.getName());
    }
}

getState()

Threads and processes are the same. There is a certain state. Is the thread started, or is the thread waiting? These are the state of the thread. getState() can get the state of the thread at this time

getPriority()

This is similar to the priority of a process. There may be multiple thread PCBs in a process. The priority determines which PCB will be scheduled first

isDaemon()

We need to know this about background threads. The JVM will not end until all non background threads of a process end

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hehhehhe");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        System.out.println(myThread.isDaemon());
    }
}

isAlive()

isInterrupted()

isInterrupted() can determine whether the thread is interrupted

Tags: Java Back-end JavaEE IDEA

Posted by mrmitch on Sun, 17 Apr 2022 06:36:22 +0930