JUC high concurrency programming

JUC high concurrency programming

1. Introduction to JUC

  1. In Java, the thread part is a key point. JUC is the inspection of the Java.util.concurrent toolkit, which is a toolkit for processing threads. JDK1.5 began to appear

  2. Processes and threads:

    • Process: an application running in the system; Once a program runs, it is a process, which is the smallest unit of resource allocation
    • Thread: the basic unit in which the system allocates processor time resources, or an execution flow executed independently within a process. The smallest unit of program execution.
  3. Status of thread:

    1. New new
    2. Runnable ready
    3. Blocked
    4. Waiting
    5. TimedWaiting (obsolete)
    6. Terminated
  4. Difference between Wait and Sleep

    1. sleep is the static method of Thread and wait is the method of Object. Any Object can be called by real columns
    2. sleep does not release the lock, nor does it need to occupy the lock. wait releases the lock, but the premise for calling it is that the current thread occupies the lock (that is, the code should be in synchronized)
    3. They can all be interrupted by the interrupted method
  5. Concurrency and parallelism

    1. Let's start with: serial and parallel

      1. Serial mode: only one task can be acquired and executed at a time.
      2. Parallel mode: obtain multiple tasks at the same time and execute the obtained tasks at the same time.
    2. Concurrency: it refers to the imagination that multiple programs can run at the same time. More specifically, multiple threads can run at the same time or multiple instructions can run at the same time

    3. Concurrency: multiple threads are accessing the same resource at the same time, and multiple threads are connected to one point

      For example: Spring Festival transportation ticket grabbing, e-commerce second kill

    4. Parallel: multiple tasks are executed together and then summarized

      For example: soak instant noodles, boil water in an electric kettle, tear the seasoning bag and pour it into the bucket

  6. Tube side

    1. Monitor (called monitor in operating system and lock in Java): it is a synchronization mechanism to ensure that only one thread accesses protected data or code at the same time
    2. The same in the Jvm is based on entry and exit and is implemented using a management object
  7. User thread and daemon thread

    1. User threads: Custom threads. Most of them are user threads

      Case: the main thread ends: the user thread is still running and the jvm is alive

    package com.codetip.codejuc.juc;
    
    public class Test01 {
        public static void main(String[] args) {
            // isDaemon indicates whether it is a user thread or a daemon thread
            // true: daemon thread false user thread
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
                // Set the loop not to terminate
                while (true) {
    
                }
            }, "aa").start();
    
            System.out.println(Thread.currentThread().getName() + "  Over");
        }
    }
    
    

     

    1. Daemon thread: a specific thread in the background, such as garbage collection

      Case: without user threads, the jvm will end if all threads are daemon threads

    package com.codetip.codejuc.juc;
    
    public class Test01 {
        public static void main(String[] args) {
            // isDaemon indicates whether it is a user thread or a daemon thread
            // true: daemon thread false user thread
            Thread aa = new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
                while (true) {
    
                }
            }, "aa");
            // Set thread to daemon
            aa.setDaemon(true);
            aa.start();
            System.out.println(Thread.currentThread().getName() + "  Over");
        }
    }
    // The execution results are shown in the figure below
    

 

 

2. Lock interface

  1. Review Synchronized: Synchronized is a keyword in Java. It is a kind of synchronization lock. There are the following types of modified objects (scope of action)

    1. synchronized scope

      // Decorated code block
      synchronized(this){
          // Modify a code block. The modified code block is a synchronization method. Its scope is the code in braces {}, and the object is the object calling the code block.
      }
      
      // Modify a method 
      public synchronized add(){
         // Modify a code block. The modified code block is a synchronous method. Its scope is the whole method, and the object is the object calling the method
          
      }
      
      // Modify a static method
      public static synchronized save(){
          // Modifies a static method, the scope of action is the whole static method, and the action object is all objects of this class
      }
      // Decorate a class
      public synchronized class test001(){
          // The scope is the content enclosed in braces after synchronized, and the scope object is all objects of this class
      }
      
    2. Multithreaded programming steps

      1. Create a resource class, and create the methods and properties of the resource class
      2. Operation methods in resource class: 1. Judge 2. Work 3. Notify
      3. Create multiple threads and call the operation methods of the resource class
    3. Several ways to create threads

      1. Integrate Thread class (generally not used. In java, it is single inheritance, and inheritance is very precious)
      2. Implement Runnable interface
      3. Use the Callable interface (explained later)
      4. Using thread pool (explained later)
    4. Example of synchronizing ticket purchase

      1. Three conductors, selling 30 tickets

        package com.codetip.codejuc.juc.sync;
        
        // The first step is to create a resource class and define properties and operation methods
        class Ticket {
            // Number of votes
            private int number = 30;
        
            // Ticketing method
            public synchronized void sale() {
                // Ticket buying process
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + ":Sell a ticket: " + 1 + "   surplus:" + --number);
                }
            }
        }
        
        public class SaleTicked {
        
            public static void main(String[] args) {
                Ticket ticket = new Ticket();
                // Thread one
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 40; i++) {
                            ticket.sale();
                        }
        
                    }
                }, "aa").start();
        
                // Thread two
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 40; i++) {
                            ticket.sale();
                        }
                    }
                }, "bb").start();
        
                // Line Cheng San
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 40; i++) {
                            ticket.sale();
                        }
                    }
                }, "cc").start();
        
        
            }
        }
        
        
  2. Lock interface

    1. Description: provides a framework interface and class for lock and wait conditions. It is different from the built-in synchronization and monitor. Details: check the API document (Baidu)
    2. It is not always necessary to call the start method in the thread to create the thread immediately. There is a native keyword, which calls the command of the operating system. If the system is idle at that time, a thread may be created immediately.

    Rewrite the ticketing code with lock:

    package com.codetip.codejuc.juc.lock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    // The first step is to create a resource class and define properties and operation methods
    class LockTicket {
        private final Lock lock = new ReentrantLock();
        // Number of votes
        private int number = 30;
    
        // Ticketing method
        public void sale() {
            try {
                // Lock
                lock.lock();
                // Ticketing process
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + ":Sell a ticket: " + 1 + "   surplus:" + --number);
                }
            } finally {
                // Unlock
                lock.unlock();
            }
        }
    }
    
    public class LockTicked {
    
        public static void main(String[] args) {
            LockTicket ticket = new LockTicket();
            // Thread one
            new Thread(() -> {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
    
            }, "aa").start();
    
            // Thread two
            new Thread(() -> {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }, "bb").start();
    
            // Line Cheng San
            new Thread(() -> {
    
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }, "cc").start();
    
    
        }
    }
    
    

3. Inter thread communication

  1. Case: there are two threads to implement a variable with an initial value of 0. A thread pair value plus 1 and a thread pair value minus 1

    // Using the synchronized keyword
    package com.codetip.codejuc.juc.number;
    
    // The first step is to create a resource class and define properties and methods
    class Share {
        // attribute
        private int num = 0;
    
        // Method plus 1
        public synchronized void incr() throws InterruptedException {
            // Judge, work, inform
            if (num != 0) { // Judge whether num is equal to 0. If not, wait
                this.wait();
            }
            // If num is 0, add 1
            num++;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    
        // Method minus 1
        public synchronized void decr() throws InterruptedException {
            // Judge, work, inform
            if (num != 1) { // Judge whether num is equal to 1. If not, wait
                this.wait();
            }
            // If num is 0, subtract 1
            num--;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    }
    
    public class Number {
        public static void main(String[] args) {
            Share share = new Share();
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.incr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "a").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.decr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "b").start();
    
        }
    }
    
    

    The results are as follows:

        

 

  1. False wake-up problem: add two threads c and d in the code

    package com.codetip.codejuc.juc.number;
    
    // The first step is to create a resource class and define properties and methods
    class Share {
        // attribute
        private int num = 0;
    
        // Method plus 1
        public synchronized void incr() throws InterruptedException {
            // Judge, work, inform
            if (num != 0) { // Judge whether num is equal to 0. If not, wait
                this.wait();
            }
            // If num is 0, add 1
            num++;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    
        // Method minus 1
        public synchronized void decr() throws InterruptedException {
            // Judge, work, inform
            if (num != 1) { // Judge whether num is equal to 1. If not, wait
                this.wait();
            }
            // If num is 0, subtract 1
            num--;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    }
    
    public class Number {
        public static void main(String[] args) {
            Share share = new Share();
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.incr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "a").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.decr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "b").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.incr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "c").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.decr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "d").start();
    
    
        }
    }
    

    Execution results:

     

    See a different effect than expected

    The reason for this is: wait here. Specific instructions in wait in API: for the version that touches a parameter, it is possible to realize interrupt and false wake-up, and this method should always be used in the loop

    In fact, the reason is: A will wake up other locks after normal execution, but after wake-up, the thread cannot determine which is executing, and the characteristics of the wait method are where to sleep and where to wake up, so some threads do not execute the judgment method again.

    The modified code is as follows: (modify if to a while loop)

    package com.codetip.codejuc.juc.number;
    
    // The first step is to create a resource class and define properties and methods
    class Share {
        // attribute
        private int num = 0;
    
        // Method plus 1
        public synchronized void incr() throws InterruptedException {
            // Judge, work, inform
            while (num != 0) { // Judge whether num is equal to 0. If not, wait
                this.wait();
            }
            // If num is 0, add 1
            num++;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    
        // Method minus 1
        public synchronized void decr() throws InterruptedException {
            // Judge, work, inform
            while (num != 1) {
                this.wait();
            }
            // If num is 1, subtract 1
            num--;
            System.out.println(Thread.currentThread().getName() + "The value is:" + num);
            // Notify other threads
            this.notifyAll();
        }
    }
    
    public class Number {
        public static void main(String[] args) {
            Share share = new Share();
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.incr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "a").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.decr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "b").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.incr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "c").start();
    
            new Thread(() -> {
                for (int i = 1; i <= 10; i++) {
                    try {
                        share.decr();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "d").start();
        }
    }
    

    The results are as follows:

     

  2. Implementation through lock interface

    Create Lock class

    Create a monitoring class for lock,

     Lock lock = new ReentrantLock(); // Monitor condition of lock = lock. Newcondition();
    

package com.codetip.codejuc.juc.number;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;// Step 1: create a resource class and define the attribute and method class ShareL {/ / attribute private int num = 0; lock lock = new reentrantlock(); / / monitor condition of lock = lock. Newcondition(); / / method plus 1 public void incr() throws interruptedexception {/ / judge, work and notify lock. Lock(); try {while (Num! = 0) {/ / judge whether num is equal to 0. If not, wait for condition.await();} / / if num is 0, add 1 to operate num + +; system.out.println (thread. Currentthread(). Getname() + "value is:" + num); / / notify other threads of condition. Signalall() ;} finally {lock. Unlock();}} / / method minus 1 public void decr() throws interruptedexception {lock. Lock(); try {/ / judge, work and notify while (Num! = 1) {condition.await();} //If num is 1, subtract 1. Operate num --; system. Out. Println (thread. Currentthread(). Getname() + "value is:" + num); / / notify other threads of condition. Signalall();} finally {lock. Unlock();}}} public class locknumber {public static void main (string [] args) {        ShareL share = new ShareL();        new Thread(() -> {            for (int i = 1; i <= 10; i++) {                try {                    share.incr();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "a").start();        new Thread(() -> {            for  (int i = 1; i <= 10; i++) {                try {                    share.decr();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "b").start();        new Thread(() -> {            for (int i = 1; i <= 10; i++) {                try {                    share.incr() ;                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "c").start();        new Thread(() -> {            for (int i = 1; i <= 10; i++) {                try {                    share.decr();                } catch (InterruptedException e)  {                    e.printStackTrace();                }            }        }, "d").start();    }}

4. Customized communication between threads

Causes threads to execute in the specified order

Case: start three threads, AA print five times, BB print 10 times, CC print 15 times, and conduct 10 rounds of test

Scheme: design a flag bit flag ==1 for printing, modify the flag bit, notify BB, and so on AA flag==2 BB flag ==3 CC

package com.codetip.codejuc.juc.custom;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;class ShareResource {    // Custom flag bit private int flag = 1; // 1:AA 2:BB 3:CC / / create Lock lock = new ReentrantLock(); / / create three conditions (equivalent to listening); Condition C1 = lock. Newcondition(); Condition C2 = lock. Newcondition(); Condition C3 = lock. Newcondition(); / / print public void print5 (int loop) five times Throws interruptedexception {/ / step 1 lock. Lock(); try {/ / put it into the loop to prevent false wake-up while (flag! = 1) {C1. Await();} for (int i = 1; I < = 5; I + +) {system.out.println (thread. Currentthread(). Getname() + "loop value:" + I "+ "The current is the" + loop + "round");} / / modify the flag bit to notify BB flag = 2; C2. Signal();} finally {lock. Unlock();}} / / print public void print10(int loop) throws InterruptedException {/ / step 1 lock. Lock(); try {/ / put it into the loop to prevent false wake-up while (flag! = 2) {C2. Await();} for (int i = 1; I < = 10; I + +) {system.out.println (thread. Currentthread(). Getname() + "value of loop:" + I + "current" + loop + "round");} //Modify flag bit notification CC flag = 3; C3. Signal();} finally {lock. Unlock();}} / / print public void print15(int loop) throws InterruptedException {/ / step 1 lock. Lock(); try {/ / put it into the loop to prevent false wake-up while (flag! = 3) {C3. Await();} for (int i = 1; I < = 15; I + +) {system.out.println (thread. Currentthread(). Getname() + "value of loop:" + I + "current" + loop + "round");} //Modify flag bit notification AA flag = 1; C1. Signal();} finally {lock. Unlock();}}} public class threadprint {public static void main (string [] args) {shareresource shareresource = new shareresource(); new thread (() - > {for (int i = 0; I < = 10; I + +) {                try {                    shareResource.print5(i);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "AA").start();        new Thread(() -> {            for (int i = 0; i <= 10; i++) {                try {                    shareResource.print10(i) ;                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "BB").start();        new Thread(() -> {            for (int i = 0; i <= 10; i++) {                try {                    shareResource.print15(i);                } catch (InterruptedException e)  {                    e.printStackTrace();                }            }        }, "CC").start();    }}

The operation is as follows:

 

Keywords: Java

Added by whatever on Tue, 30 Nov 2021 22:09:20 +0200