Java se multithreading

Understanding of programs, processes and threads

1. Program

Concept: it is a set of instructions written in a certain language to complete a specific task. It refers to a piece of static code, static object.

2. Process

Concept: an execution process of a program, or a running program

Note: as the unit of resource allocation, the system will allocate different memory areas for each process at run time

3. Thread

Concept: a process can be further refined into a thread, which is an execution path within a program.

Note: thread is the unit of scheduling and execution. Each thread has an independent running stack and program counter (pc). The overhead of thread switching is small


Each thread has its own independent stack and program counter (pc)

Multiple threads share the structure in the same process: method area and heap

Understanding of single core cpu and multi-core cpu

Single core is actually a fake multithreading, because only one thread can be executed in a time unit.
If it is multi-core, it can give better play to the efficiency of multithreading. (today's servers are multi-core)
A Java application Exe, in fact, there are at least three threads: main() main thread, gc() garbage collection thread and exception handling thread. Of course, if an exception occurs, it will affect the main thread.

Parallelism and concurrency

Parallel: multiple CPU s execute multiple tasks at the same time. For example, many people do different things at the same time.

Concurrency: one CPU (using time slice) executes multiple tasks at the same time. For example: second kill, multiple people do the same thing.

Four ways to create multithreading

1. Method of inheriting Thread class

start() function:
1. Start the current thread
2. Run the current thread (run)
be careful:
3. * * you cannot directly call run() * * to start a thread, which is a single thread, not a multi thread
4. When another thread is started, the thread that has started () cannot be executed again. An illegalThread exception will be reported, and an object of thread subclass needs to be re created

public class ThreadTest {
    public static void main(String[] args) {
        //3. Create objects of subclasses of Thread class
        MyThread thread = new MyThread();
        //4. Call start() through this object
        thread.start();//Thread 1
//        thread.run();
//        thread.start();
        MyThread thread1 = new MyThread();
        thread1.start();//Thread 3

        for (int i=0;i<100;i++){//Thread 2
            if(i%2==0){
                System.out.println(i+"***main***");
            }
        }
        new Thread(){//You can also use multithreading with methods that anonymously subclass anonymous objects
            @Override
            public void run() {
                super.run();
            }
        }.start();
    }
}
//1. Create a subclass inherited from Thread class
class MyThread extends Thread {
    //2. Override run() -- > of Thread class to declare the operation executed by this Thread in run()
    public void run(){
        for(int i=0;i<100;i++){
            if(i % 2 == 0){
                System.out.println(i);
            }
        }
    }
}

2. Implement Runnable interface

//1. Create a class that implements the Runnable interface
class MyThread1 implements Runnable{
    @Override
//2. Implement the class to implement the abstract method in Runnable: run()
    public void run() {
        for(int i=0;i<100;i++){
            if(i%2 ==0){
                System.out.println(i);
            }
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
//        3. Create an object that implements the class
        MyThread1 myThread1 = new MyThread1();
//        4. Pass this object as a parameter to the constructor of Thread class and create the object of Thread class
        Thread thread = new Thread(myThread1);
        thread.setName("Thread two");
//        5. Call start() through the Thread class object
//          5.1 start thread
//          5.2 call the run() of the current thread, but because it is implemented rather than inherited, it is not the way to call the rewritten run()
//             By viewing the source code, we can know that the constructor parameter of Thread is of Runnable type,
//             The object of the implementation class created in step 3 is put into the Thread constructor as an argument,
//             When start() is called, the run method in the Thread class will be started, and then run() of the formal parameter will be called, that is, run() of the object implementing the class
        thread.start();
    }
}

Comparison of the two methods

During development: the method of implementing Runnable interface is preferred
reason:
1. This method has no limitation of single inheritance of classes
2. This method is more suitable for dealing with the situation that multiple threads share data (the first method needs to declare static if you want to share data)

Contact: public class thread implements runnable (the first method also implements Runnable)
The same point: both methods need to override run(), and declare the logic to be executed by the thread in run()

3. Implement the callable interface

How to understand that the way to implement the Callable interface to create multithreads is more powerful than the way to implement the Runnable interface to create multithreads?

  1. call() can have a return value.
  2. call() can throw an exception, be caught by an external operation, and get the exception information
  3. Callable supports generics
//1. Create an implementation class that implements Callable
class NumThread implements Callable{
    //2. Implement the call method and declare the operation to be executed by this thread in call()
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public class ThreadNew {
    public static void main(String[] args) {
        //3. Create an object of the Callable interface implementation class
        NumThread numThread = new NumThread();
        //4. Pass the object of this Callable interface implementation class to the FutureTask constructor as an object to create the FutureTask object
        FutureTask futureTask = new FutureTask(numThread);
        //5. Pass the FutureTask object as a parameter to the constructor of the Thread class, create the Thread object, and call start()
        new Thread(futureTask).start();

        try {
            //6. Get the return value of call method in Callable
            //The return value of get() is the return value of call() overridden by the FutureTask constructor parameter Callable implementation class.
            Object sum = futureTask.get();
            System.out.println("The sum is:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

4. Thread pool

Benefits:

1. Improve response speed (reduce the time to create new threads)

2. Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)

3. Easy thread management
corePoolSize: the size of the core pool
maximumPoolSize: maximum number of threads
keepAliveTime: how long does the thread last when there is no task, and then it will terminate

class NumberThread implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

class NumberThread1 implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {
        //1. Provide a thread pool with a specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;//Downward transformation
        //Set the properties of the thread pool
//        System.out.println(service.getClass());
//        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();
        //2. Execute the operation of the specified thread. You need to provide an object that implements the Runnable interface or the Callable interface implementation class
        service.execute(new NumberThread());//Suitable for Runnable
        service.execute(new NumberThread1());//Suitable for Runnable

//        service.submit(Callable callable);// Suitable for callable
        //3. Close the connection pool
        service.shutdown();
    }

}

Common methods in threads

* 1.start():Start the current thread and call the run()
* 2.run():It usually needs to be rewritten Thread Class to declare the operation to be performed by the created thread in this method
* 3.currentThread():Static method that returns the thread executing the current code
* 4.getName():Gets the name of the current thread
* 5.setName():Sets the name of the current thread
*
* 6.yield():Release current cpu Even if the execution right is released, it does not necessarily execute other threads
* 7.join():In thread a Calling thread b of join(),be a Will block until b End of execution
* 8.stop(): Obsolete. When this method is executed, the current thread is forced to end.
* 9.sleep(long millitime):Make the current thread sleep the specified millitime Milliseconds, that is, this time is blocked
* 10.xxx.isAlive():Determine whether the current thread is alive

thread priority

* 1. MAX_PRIORITY:10
* 2. MIN_PRIORITY:1
* 3. NORM_PRIORITY:5 -->Default Priority 
* 4.How to get and set priority
*    getPriority():Gets the priority of the thread
*    setPriority(int p):Set thread priority
*    Note: the thread with high priority is not necessarily executed before the thread with low priority, but in terms of probability, the thread with high priority has priority over the thread with low priority

Thread life cycle

  1. Status: Five

    Method: the method used for corresponding state transition

  2. Attention: which methods are executed due to the change of state; Actively calling some methods causes a change in state

  3. The final state of the thread is death

Thread synchronization mechanism

background

Example: create three windows to sell tickets, with a total of 100 tickets. Use the method of implementing the Runnable interface

  • 1. Problem: in the process of selling tickets, there are duplicate tickets and wrong tickets -- > there are thread safety problems
  • 2. Cause of the problem: when a thread operates the ticket, and the operation has not been completed, other threads participate and operate the ticket.
  • 3. How to solve it: when a thread a is operating a ticket, other threads cannot participate. No other thread can start to operate the ticket until thread a has finished operating the ticket. This situation cannot be changed even if thread a is blocked.

Solution (using synchronization mechanism)

Method 1: synchronize code blocks

synchronized(Synchronization monitor){
        //Code to be synchronized
     }

explain:
1. The code that operates shared data is the code that needs to be synchronized.
– > you cannot include too much code or too little code (key!).
2. Shared data: variables operated by multiple threads. For example, a ticket is sharing data.
3. Synchronous monitor, commonly known as lock. The object of any class can act as a lock.
Requirement: multiple threads must share the same lock.
4. In the way of implementing the Runnable interface to create multiple threads, we can consider using this as the synchronization monitor. (the object corresponding to the class corresponding to the current method)
5. In the way of inheriting the Thread class to create multithreads, use this carefully as the synchronization monitor (because this way of inheriting needs to create objects of multiple classes, and this cannot refer to which object). Consider using the current class as the synchronization monitor.

Mode 2: synchronization method

  1. The synchronization method still involves the synchronization monitor, but does not need to be explicitly declared.
  2. Non static synchronization method. The synchronization monitor is this
    Static synchronization method. The synchronization monitor is the current class itself
class Windows3 implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while(true){//This structure is an infinite loop and needs a break to jump out of the loop
            show();
            if(ticket==0){
                break;
            }
        }
    }
  //The synchronization method needs to be modified with synchronized. Only one thread is allowed to enter the processing at the same time, and the next thread can enter after it is finished
    public synchronized void show(){//Sync monitor: this
        if(ticket >0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":Ticket No.:" + ticket);
            ticket--;
        }
    }
}
public class WindowTest3 {
    public static void main(String[] args) {
        Windows3 w = new Windows3();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3");

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

Mode 3: lock lock

class Window implements Runnable{    private int ticket = 100;    //1. Instantiate reentrantlock private reentrantlock lock = new reentrantlock()// Key @ override public void run() {while (true) {try {lock. Lock(); / / 2. Call the lock method lock() if (ticket > 0) {try {thread. Sleep (100);} catch (InterruptedException e) {                        e.printStackTrace();                    }                     System. out. println(Thread.currentThread(). Getname() + ": ticket number:" + ticket "; ticket--;                } else{                    break;                }            } Finally {lock. Unlock(); / / 3. Call unlocking method: unlock()}}}} public class locktest {public static void main (string [] args) {window w = new window(); thread T1 = new thread (W); thread T2 = new thread (W); thread T3 = new thread (W); t1.setname ("window 1"); t2.setname ("window 2"); t3. Setname ("window 3"); t1. start();         t2. start();         t3. start();    }}
  1. Interview question: what are the similarities and differences between synchronized and Lock?
    Same: both can solve thread safety problems

    Different:

    The synchronized mechanism automatically releases the synchronization monitor (automatic) after executing the corresponding synchronization code
    Lock requires manual start synchronization (lock()) and manual implementation (unlock()) to end synchronization (manual, more flexible)

  2. Priority:
    Lock -- > synchronization code block (has entered the method body and allocated corresponding resources) - -- > synchronization method (outside the method body)

Interview question: how to solve thread safety problems? There are several ways, synchronization mechanism, and four

advantages and disadvantages

The way of synchronization solves the safety problem of threads benefit

When operating synchronization code, only one thread can participate and other threads wait. It is equivalent to a single threaded process with low efficiency limitations

Singleton mode lazy thread safety

public class BankTest {    private BankTest(){    }    private static BankTest instance = null;    public static BankTest getInstance(){        if(instance == null){//Double check, first level check. If you have created an object, you do not need to enter again when multiple threads come in later, Directly return synchronized (banktest. Class) {/ / layer 2 check. The first time multiple threads come in, the object has not been created, so synchronization is required to turn on thread safety if (instance = = null) {instance = new banktest();}}} return instance;    }}

deadlock

  1. Understanding of Deadlock: different threads occupy the synchronization resources needed by the other party and do not give up. They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock
  2. explain:
    1) After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue
    2) When we use synchronization, we should avoid deadlock.
public class ThreadTest {    public static void main(String[] args) {        StringBuffer s1 = new StringBuffer();        StringBuffer s2 = new StringBuffer();        //Thread 1 new thread() {@ override public void run() {synchronized (S1) {/ / hold s1z s1.append ("a"); s2.append ("1"); try {thread.sleep (100); 	// During the sleep period, the running right is transferred to another thread. At this time, the other thread also sleeps after holding the S2 lock. The running right returns to the original thread again, but the S2 lock is required for the next synchronization problem, However, the deadlock} catch (interruptedexception E) {e.printstacktrace();} occurs because another thread holds S2 and does not release it synchronized (s2){                        s1.append("b");                        s2.append("2");                        System.out.println(s1);                        System.out.println(s2);                    }                }            }        }. start();        // Thread 2 new thread (New runnable() {@ override public void run() {synchronized (S2) {S1. Append ("C"); S2. Append ("3"); try {thread. Sleep (100);} catch (InterruptedException e) {                        e.printStackTrace();                    }                     synchronized (s1){                        s1.append("d");                        s2.append("4");                        System.out.println(s1);                        System.out.println(s2);                    }                }            }        }). start();    }}

Thread communication

Three methods involved

wait()

Once this method is executed, the current thread enters a blocking state and releases the synchronization monitor. (the key is to release the synchronization monitor)

notify()

Once this method is executed, a thread that is waiting is awakened. If multiple threads are waiting, wake up the one with higher priority.

notifyAll()

Once this method is executed, all wait ing threads will wake up.

explain

  1. The three methods can only be used in synchronous code blocks or synchronous methods. (cannot be used in lock())
  2. The caller of the three methods must be the synchronization code block or the synchronization monitor in the synchronization method. (called by the synchronization monitor), otherwise, an IllegalMonitorStateException will appear
  3. The three methods are defined in Java Lang. object class. (because the synchronization monitor can be an object of any class, these three methods must be defined in the object class to allow objects of any class to call at will.)

Interview question: what are the similarities and differences between sleep() and wait()?

​ 1. The same point: once the method is executed, the current thread can enter the blocking state.

​ 2. difference:
1) the positions of the two method declarations are different: sleep() is declared in Thread class and wait() is declared in object class
2) different requirements for calling: sleep() can be called in any required scenario. wait() must be used in a synchronization code block or synchronization method
3) whether to release the synchronization monitor: if both methods are used in the synchronization code block or synchronization method, sleep() will not release the lock (synchronization monitor), and wait() will release the lock.

Keywords: Java Multithreading

Added by Ajdija on Tue, 21 Dec 2021 09:10:00 +0200