Detailed explanation of multithreading

Detailed explanation of multithreading

summary

Core concept

  • Threads are independent execution paths
  • When the program is running, there will be multiple threads in the background, such as main thread and gc thread, even if there is no thread created by itself
  • main() is called the main thread, which is the entry of the system and is used to execute the whole program;
  • In a process, if multiple threads are opened up, the operation of threads is scheduled by the scheduler. The scheduler is closely related to the operating system, and the sequence cannot be considered as intervention.
  • When operating on the same resource, there will be the problem of resource grabbing, and concurrency control needs to be added;
  • Threads will bring additional overhead, such as cpu scheduling time and concurrency control overhead.
  • Each thread interacts in its own working memory. Improper memory control will cause data inconsistency.

Thread creation

Three creation methods

  • Inherit Thread class

    • Custom Thread class inherits Thread class
    • Rewrite the run() method and write the thread execution body
    • Create a thread object and call the start() method to start the thread
    //Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread
    
    //Summary: note that thread startup is not necessarily executed immediately, but is scheduled by cpu
    public class TestThread01 extends Thread{
        @Override
        public void run() {
            //run method thread body
            for (int i = 0; i < 200; i++) {
                System.out.println("I'm looking at the code---"+i);
            }
        }
    
        public static void main(String[] args) {
            //main thread
    
            //Create a thread object
            TestThread01 testThread01 = new TestThread01();
    
            //Call the start method to start the thread
            testThread01.start();
    
            for (int i = 0; i < 1000; i++) {
                System.out.println("I'm learning multithreading----"+i);
            }
        }
    }
    

    Network diagram Download

    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    
    //Practice Thread to realize multi-threaded synchronous downloading of pictures
    public class TestThread02 extends Thread{
        private String url;
        private String name;
    
        public TestThread02(String url,String name){
            this.url =url;
            this.name = name;
        }
        //Thread executor for downloading pictures
        @Override
        public void run() {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.Downloader(url,name);
            System.out.println("Downloaded the file named:"+name);
        }
    
        public static void main(String[] args) {
            TestThread02 testThread01 = new TestThread02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg");
            TestThread02 testThread02 = new TestThread02("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
            TestThread02 testThread03 = new TestThread02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg");
    
            //Open thread
            testThread01.start();
            testThread02.start();
            testThread03.start();
        }
    
    }
    
    //Downloader
    class WebDownloader{
        //Download method
        public void Downloader(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO Abnormal, downloader Method error!");
            }
        }
    }
    

    Not recommended: avoid the limitation of oop single inheritance

  • Implement Runnable interface

    //Multithreading using Runable
    public class MyRunnable01 implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 200; i++) {
                System.out.println("run()----"+i);
            }
        }
    
        public static void main(String[] args) {
            new Thread(new MyRunnable01()).start();
    
    
            for (int i = 0; i < 1000; i++) {
                System.out.println("main()-----"+i);
            }
        }
    
    
    }
    

    Network diagram Download

    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    
    public class MyRunnable02 implements Runnable{
        private String url;
        private String name;
    
        public MyRunnable02(String url,String name){
            this.url =url;
            this.name = name;
        }
        //Thread executor for downloading pictures
        @Override
        public void run() {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.Downloader(url,name);
            System.out.println("Downloaded the file named:"+name);
        }
    
        public static void main(String[] args) {
            MyRunnable02 mr01 = new MyRunnable02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg");
            MyRunnable02 mr02 = new MyRunnable02("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
            MyRunnable02 mr03 = new MyRunnable02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg");
    
            //Open thread
            new Thread(mr01).start();
            new Thread(mr02).start();
            new Thread(mr03).start();
        }
    }
    

    Recommended: it avoids the limitation of single inheritance, is flexible and convenient, and is convenient for the same object to be used by multiple threads

    //A resource
    StartThread4 station = new StartThread4();
    //Multiple agents
    new Thread(station,"Xiao Ming").start();
    new Thread(station,"Xiao Hong").start();
    new Thread(station,"teacher").start();
    
    //Multiple threads operate on the same object at the same time
    //Simulated ticket grabbing
    
    //Problems found: when multiple threads operate on the same resource, the thread is unsafe and the data is disordered
    public class MyRunnable03 implements Runnable{
        //Initial number of votes
        private int ticketNums = 10;
        @Override
        public void run() {
            while (true){
                if (ticketNums<=0){
                    break;
                }
                //Analog delay
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "-->Got the second" + ticketNums-- + "Tickets.");
            }
        }
    
        public static void main(String[] args) {
            MyRunnable03 myRunnable03 = new MyRunnable03();
    
            new Thread(myRunnable03,"Xiao Ming").start();
            new Thread(myRunnable03,"teacher").start();
            new Thread(myRunnable03,"Scalpers").start();
        }
    }
    
  • Implement Callable interface

    1. To implement the Callable interface, the return value type is required

    2. When rewriting the call method, you need to throw an exception

    3. Create target object

    4. Create execution service: executorservice ser = executors newFixedThreadPool(1);

    5. Submit execution: future result1 = Ser submit(t1);

    6. Get the result: Boolean R1 = result1 get()

    7. Close the service: Ser shutdownNow();

    import com.sun.org.apache.xpath.internal.operations.Bool;
    
    import java.util.concurrent.*;
    
    //Thread creation method 3: implement Callable interface
    /*
    callable Benefits of
    1.Can have return value
    2.Throw exception
     */
    public class MyCallableDemo01 implements Callable<Boolean> {
        private String url;
        private String name;
    
        public MyCallableDemo01(String url,String name){
            this.url =url;
            this.name = name;
        }
        //Thread executor for downloading pictures
        @Override
        public Boolean call() {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.Downloader(url,name);
            System.out.println("Downloaded the file named:"+name);
            return true;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            MyCallableDemo01 md01 = new MyCallableDemo01("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg");
            MyCallableDemo01 md02 = new MyCallableDemo01("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
            MyCallableDemo01 md03 = new MyCallableDemo01("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg");
    
            //Execute service creation
            ExecutorService ser = Executors.newFixedThreadPool(3);
    
            //Submit for execution
            Future<Boolean> result1 = ser.submit(md01);
            Future<Boolean> result2 = ser.submit(md02);
            Future<Boolean> result3 = ser.submit(md03);
    
            //Get results
            boolean r1 = result1.get();
            boolean r2 = result2.get();
            boolean r3 = result3.get();
    
            //Shut down service
            ser.shutdown();
        }
    }
    

Case: Tortoise rabbit race

//Tortoise and rabbit race
public class Race implements Runnable{

    //winner
    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //Judge whether the game is over
            boolean flag = gameOver(i);
            if (flag){//The game is over, stop the game
                break;
            }

            //Rabbit sleep
//            if (Thread.currentThread().getName().equals("rabbit") & & I% 10 = = 0){
//                try {
//                    Thread.sleep(1);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }

            System.out.println(Thread.currentThread().getName() + "-->Run away" + i + "step");
        }
    }
    //Determine whether the game is over
    private boolean gameOver(int steps){
        if (steps>=100){
            winner = Thread.currentThread().getName();
            System.out.println("winner is" + winner);
            return true;
        }
        if (winner!=null){//There are already winners
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();

        new Thread(race,"rabbit").start();
        new Thread(race,"tortoise").start();
    }
}

Static proxy

package proxystatic;

//Static proxy
public class StaticProxy {
    public static void main(String[] args) {
        new Wedding(new You()).HappyMarry();
    }

}

interface Marry{
    void HappyMarry();
}

//Real character, you get married
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("I'm married, very happy!");
    }
}

//Acting role to help you get married
class Wedding implements Marry{

    private Marry target;

    public Wedding(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    private void after() {
        System.out.println("After marriage, you need the final payment");
    }

    private void before(){
        System.out.println("Before marriage, you need to decorate the scene");

    }
}

Lamda expression

  • Avoid too many anonymous inner class definitions

  • Its essence belongs to the concept of functional programming

    (params) -> expression[expression]
     (params) -> statement[sentence]
      (params) -> {statements}
    

    a-> System.out.println("i like lambda-->"+a)

    ``new Thread(()->System. out. Println ("multi thread learning...) start();`

  • Definition of functional interface: any interface is a functional interface if it contains only one abstract method. Functional interfaces can create objects of the interface through lambda expressions.

package lambdaShow;

public class TestLambda01{
    //3. Static internal class
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4. Local internal class
        class Like3 implements ILike{

            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }

        like = new Like3();
        like.lambda();


        //5. Anonymous inner class
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();


        //6.lambda expression
        like = () -> {
            System.out.println("I like lambda5");
        };
        like.lambda();
    }
}

//Define a functional interface
interface ILike{
    void lambda();
}

//2. Implementation class
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}
package lambdaShow;

//Summary: lambda expressions can be simplified into one line only when there is one line of code. If there are multiple lines, wrap them with code blocks.
//The premise is that the interface is functional
//You can also remove parameter types from multiple parameters. To remove all parameters, parentheses must be added
public class TestLambda02 implements ILove{

    @Override
    public void Love(int hours) {
        System.out.println("I love you--" + hours);
    }

    public static void main(String[] args) {
        ILove love = null;

        love = (int hours) -> {
            System.out.println("I love you,too ---" + hours);
        };
        //1. The first simplified omitting parameter
        love = (hours)->{
            System.out.println("I love you,too ---" + hours);
        };

        //2. The second simplification omits parentheses
        love = hours->{
            System.out.println("I love you,too ---" + hours);
        };

        //3. The third simplification omits curly braces
        love = hours-> System.out.println("I love you,too ---" + hours);

        love.Love(5201314);
    }

}

interface ILove{
    void Love(int hours);
}

Thread state

  • Thread method
methodexplain
setPriority(int newPriority)Change the priority of a thread
static void sleep(long millis)Hibernates the currently executing thread for the specified number of milliseconds
void join()Wait for the thread to terminate
static void yield()Pauses the currently executing thread object and executes other threads
void interrupt()Interrupt the thread. Don't do it this way
boolean isAlive()Test whether the thread is active
  • Thread stop

    • The stop()\destroy() method provided by JDK is not recommended. (abandoned)
    • It is recommended that the thread stop by itself
    • It is recommended to use a flag bit to terminate. If the variable flag=false, the thread will be terminated.
    public class TestStop01 implements Runnable{
    
        //Set a flag bit
        private boolean flag = true;
        @Override
        public void run() {
            int i = 0;
            while (flag){
                System.out.println("run. . . . Runnable" + i++);
            }
        }
    
        //Set an open method to stop the thread and convert the flag bit
        public void stop(){
            this.flag = false;
        }
    
    
        public static void main(String[] args) {
            TestStop01 testStop01 = new TestStop01();
            new Thread(testStop01).start();
            for (int i = 0; i < 1000; i++) {
                if (i==900){
                    //Call the stop method to stop the thread
                    testStop01.stop();
                    System.out.println("The thread stopped");
                }
                System.out.println("main--" + i);
            }
    
        }
    }
    
  • Thread sleep

    • Sleep specifies the number of milliseconds the current thread is blocking
    • Exception InterruptedException in sleep
    • When the sleep time arrives, the thread enters the ready state;
    • sleep can simulate network delay, countdown, etc.
    • Every object has a lock, and sleep will not release the lock.
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class TestSleep01 {
    
        public static void main(String[] args) throws InterruptedException {
            timeDown();
    
            Date startTime = new Date(System.currentTimeMillis());//Get current system time
    
            while (true){
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH-mm-ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());//Get current system time
            }
        }
    
        public static void timeDown() throws InterruptedException {
            int time = 10;
    
            while (true){
                Thread.sleep(1000);
                System.out.println(time--);
                if (time<=0){
                    break;
                }
            }
        }
    }
    
  • Thread comity

    • Comity thread: pause the currently executing thread without blocking it
    • Change the thread from running state to ready state
    • Let the cpu reschedule, comity is not necessarily successful! Look at your mood
    public class TestYield01 {
        public static void main(String[] args) {
            MyYield myYield = new MyYield();
            new Thread(myYield,"A").start();
            new Thread(myYield,"B").start();
        }
    
    }
    class MyYield implements Runnable{
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "The thread starts executing");
            Thread.yield();//Thread comity
            System.out.println(Thread.currentThread().getName() + "Thread stop execution");
        }
    
    
  • Join

    • Join merge threads. After this thread completes execution, execute other threads. Other threads are blocked
    • Imagine jumping in line
    public class TestJoin implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 500; i++) {
                System.out.println("Threaded VIP coming" + i);
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            TestJoin testJoin = new TestJoin();
            Thread thread = new Thread(testJoin);
            thread.start();
    
            for (int i = 0; i < 300; i++) {
                if (i == 20){
                    thread.join();//Jump in line
                }
                System.out.println("main" + i);
            }
        }
    }
    
  • Thread state observation

    • Thread.State

      NEW: threads that have not been started are in this state.

      RUNNABLE: the thread executing in the java virtual machine is in this state

      BLOCKED: the thread that is BLOCKED waiting for the monitor to lock is in this state

      WAITING: the thread that is WAITING for another thread to perform a specific action is in this state

      TIMED_WAITING: the thread that is waiting for another thread to execute the action for the specified waiting time is in this state.

      TERMINATED: the exited thread is in this state

    //Observe the status of the thread
    public class TestState {
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("///");
            });
    
            //Observe the state when the thread has not been opened
            Thread.State state = thread.getState();
            System.out.println(state);//NEW
    
    
            //After the observation is started
            thread.start();
            System.out.println(thread.getState());
    
            while (state != Thread.State.TERMINATED){//As long as the thread does not terminate, it will always output the state
                Thread.sleep(1000);
                state = thread.getState();//Update status
                System.out.println(state);//Output status
            }
        }
    }
    
  • thread priority

    • java provides a thread scheduler to monitor all threads that enter the ready state after startup. The thread scheduler determines which thread should be scheduled to execute according to priority.

    • The priority of threads is expressed in numbers, ranging from 1 to 10

      Thread.MIN_PRIORITY=1;

      Thread.MAX_PRIORITY=10;

      Thread.NORM_PRIORITY=5;

    • Change or obtain priorities in the following ways

      getPriority() setPriority(int xxx)

    //Test thread priority
    //Threads with higher thread optimization level do not necessarily execute first.
    public class TestPriority {
        public static void main(String[] args) {
            //Print priority of main thread
            System.out.println(Thread.currentThread().getName()+"-->" + Thread.currentThread().getPriority());
    
            MyPriority myPriority = new MyPriority();
    
            Thread t1 = new Thread(myPriority);
            Thread t2 = new Thread(myPriority);
            Thread t3 = new Thread(myPriority);
            Thread t4 = new Thread(myPriority);
    
    
            t1.setPriority(6);
            t1.start();
    
            t2.setPriority(2);
            t2.start();
    
            t3.setPriority(Thread.MAX_PRIORITY);
            t3.start();
    
            t4.setPriority(1);
            t4.start();
        }
    
    }
    class MyPriority implements Runnable{
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"-->" + Thread.currentThread().getPriority());
        }
    }
    
  • Daemon thread

    • Threads are divided into user threads and daemon threads
    • The virtual machine must ensure that the user thread has completed execution
    • The virtual machine does not have to wait for the daemon thread to finish executing
    • For example, recording operation logs in the background, monitoring memory, garbage collection and waiting
    //Daemon thread
    public class TestDaemon {
    
        public static void main(String[] args) {
            God god = new God();
            Person person = new Person();
    
            Thread thread = new Thread(god);
            thread.setDaemon(true);//Set daemon thread
            thread.start();//Open daemon thread
    
            thread = new Thread(person);
            thread.start();//Human thread start
        }
    
    }
    
    //lord
    class God implements Runnable{
    
        @Override
        public void run() {
            while (true){
                System.out.println("God is watching over you!");
            }
        }
    }
    
    
    //people
    class Person implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 36500; i++) {
                System.out.println("People live happily every day");
            }
    
            System.out.println("Say goodbye to the world---------------------------------");
        }
    } 
    

Thread synchronization mechanism

  • Concurrency: the same object is operated by multiple threads at the same time
  • Thread synchronization: when dealing with multithreading, multiple threads access the same object, and some threads also want to modify the object At this time, we need thread synchronization. Thread synchronization is a waiting mechanism. Multiple threads that need to access this object at the same time enter the waiting pool of this object to form a queue, wait for the previous thread to be used, and then use the next thread.
  • Queue and lock: in order to ensure the correctness of data access in the method, the lock mechanism synchronized is added during access. When one thread obtains the exclusive lock of the object and monopolizes resources, other threads must wait and release the lock after use. The following problems exist:
    • Holding a lock by one thread will cause all other threads that need the lock to hang
    • In multi thread competition, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems;
    • If a high priority thread waits for a low priority thread to release the lock, it will lead to priority inversion and performance problems.

Three examples of unsafe threads

//Unsafe ticket buying
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Forced me").start();
        new Thread(buyTicket,"Awesome you").start();
        new Thread(buyTicket,"Damn cattle").start();
    }

}
class BuyTicket implements Runnable{
    private int tickets = 10;
    boolean flag = true;

    @Override
    public void run() {
        while (flag){
            Buy();
        }
    }

    private void Buy(){
        if (tickets<=0){
            flag = false;
        }
        System.out.println(Thread.currentThread().getName() + "Bought the second" + tickets-- +"Ticket");
    }
}
//Unsafe withdrawal
//Two people go to the bank to withdraw money and open an account
public class UnsaftBank {
    public static void main(String[] args) {
        Account account = new Account(100,"Bank of China savings card");

        new Drawing(account,50,"you").start();
        new Drawing(account,100,"wife").start();
    }

}

//account
class Account{
    int money;//balance
    String name;//Card name

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}


//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;//bank account
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
    int nowMoney;

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        if (drawingMoney>account.money){
            System.out.println(Thread.currentThread().getName()+"Sorry, the balance is insufficient!");
            return;
        }

        //Thread hibernation, amplifying insecurity
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Card balance = balance - the money you withdraw
        account.money = account.money-drawingMoney;
        //The money in your hand
        nowMoney += drawingMoney;
        System.out.println(this.getName() + "Yes" + drawingMoney + "Ten thousand yuan");
        System.out.println(this.getName()+"In hand" + nowMoney + "Ten thousand yuan");
        System.out.println("Balance and" + account.money + "Ten thousand yuan");

    }
}
import java.util.ArrayList;
import java.util.List;

//Thread unsafe collection
//It is possible that several threads operate at the same location at the same time
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}

Synchronization method and synchronization block

  • Synchronization method

    • Synchronized keyword: there are two uses: synchronized method and synchronized block

      Synchronization method: public synchronized void method(int args) {}

    • The synchronized method controls the access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before it can be executed. Otherwise, the thread will be blocked. Once the method is executed, it will monopolize the lock until the method returns. The lock will not be released until the method returns. The blocked thread can obtain the lock and continue to execute

Defect: declaring a large method synchronized will affect efficiency

  • Disadvantages of synchronization method

    Only the contents that need to be modified in the method need to be locked. Too many locks waste resources

  • Synchronization block

    • synchronized(Obj){}
    • Obj is called synchronization monitor
      • Obj can use any object, but it is recommended to use shared resources as synchronization monitor
      • There is no need to specify a synchronization monitor in the synchronization method, because the synchronization monitor of the synchronization method is this, the object itself, or class
    • Synchronization monitor execution process
      • The first thread accesses, locks the synchronization monitor, and executes the code in it
      • The second thread accesses and finds that the synchronization monitor is locked and cannot be accessed
      • After the first thread is accessed, unlock the synchronization monitor
      • The second thread accesses, finds that the synchronization monitor has no lock, and then locks and accesses.

Three unsafe thread modifications

//Unsafe ticket buying
//Use synchronized to make threads safe
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Forced me").start();
        new Thread(buyTicket,"Awesome you").start();
        new Thread(buyTicket,"Damn cattle").start();
    }

}
class BuyTicket implements Runnable{
    private int tickets = 10;
    boolean flag = true;//External stop mode

    @Override
    public synchronized void run() {
        //Buy a ticket
        while (flag){
            try {
                Buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void Buy() throws InterruptedException {
        if (tickets<=0){
            flag = false;
            return;
        }
        //Analog delay
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName() + "Bought the second" + tickets-- +"Ticket");
    }
}
//Unsafe withdrawal
//Two people go to the bank to withdraw money and open an account
public class UnsaftBank {
    public static void main(String[] args) {
        Account account = new Account(1000,"Bank of China savings card");

        new Drawing(account,50,"you").start();
        new Drawing(account,100,"wife").start();
    }

}

//account
class Account{
    int money;//balance
    String name;//Card name

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}


//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;//bank account
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
    int nowMoney;

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        //The object of the lock is the amount of change
        synchronized (account){
            if (drawingMoney>account.money){
                System.out.println(Thread.currentThread().getName()+"Sorry, the balance is insufficient!");
                return;
            }

            //Thread hibernation, amplifying insecurity
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //Card balance = balance - the money you withdraw
            account.money = account.money-drawingMoney;
            //The money in your hand
            nowMoney += drawingMoney;
            System.out.println(this.getName() + "Yes" + drawingMoney + "Ten thousand yuan");
            System.out.println(this.getName()+"In hand" + nowMoney + "Ten thousand yuan");
            System.out.println("Balance and" + account.money + "Ten thousand yuan");

        }
    }
}
import java.util.ArrayList;
import java.util.List;

//Thread unsafe collection
//It is possible that several threads operate at the same location at the same time
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(3000);//Thread hibernation is not added here, but the data is abnormal because the main thread has finished running and the thread has not finished running

        System.out.println(list.size());
    }
}

CopyOnWriteArrayList

import java.util.concurrent.CopyOnWriteArrayList;

//Test the collection of JUC security types
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(list.size());
    }
}

deadlock

Multiple threads are waiting for each other to release resources and stop execution

When a synchronization block has "locks of more than two objects" at the same time, the problem of "deadlock" may occur.

Four necessary conditions for deadlock generation:

  • Mutually exclusive condition: a resource can only be used by one process at a time
  • Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources
  • Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived before they are used up
  • Circular waiting condition: a circular waiting resource relationship is formed between several processes.

Deadlock condition

public class DeadLock {
    public static void main(String[] args) {
        MakeUp g1 = new MakeUp(0,"Grey Gu Liang");
        MakeUp g2 = new MakeUp(1,"Snow White");
        g1.start();
        g2.start();
    }
}

//Lipstick
class LipStick{

}

//mirror
class Mirror{

}

//Make up
class MakeUp extends Thread{
    //A resource
    static LipStick lipStick = new LipStick();
    static Mirror mirror = new Mirror();

    int choice = 0;//Selection order
    String girlName;

    MakeUp(int choice,String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }


    @Override
    public void run() {
       makeup();
    }


    private void makeup(){
        if (choice == 0){
            synchronized (lipStick){
                System.out.println(this.girlName + "Got the lock of lipstick");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mirror){
                    System.out.println(this.girlName + "Got the lock of the mirror");
                }
            }
        }else {
            synchronized (mirror){
                System.out.println(this.girlName + "Got the lock of the mirror");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lipStick){
                    System.out.println(this.girlName + "Got the lock of lipstick");
                }
            }
        }
    }
}

Resolve deadlock

public class DeadLock {
    public static void main(String[] args) {
        MakeUp g1 = new MakeUp(0,"Grey Gu Liang");
        MakeUp g2 = new MakeUp(1,"Snow White");
        g1.start();
        g2.start();
    }
}

//Lipstick
class LipStick{

}

//mirror
class Mirror{

}

//Make up
class MakeUp extends Thread{
    //A resource
    static LipStick lipStick = new LipStick();
    static Mirror mirror = new Mirror();

    int choice = 0;//Selection order
    String girlName;

    MakeUp(int choice,String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }


    @Override
    public void run() {
       makeup();
    }


    private void makeup(){
        if (choice == 0){
            synchronized (lipStick){
                System.out.println(this.girlName + "Got the lock of lipstick");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            synchronized (mirror){
                System.out.println(this.girlName + "Got the lock on the mirror");
            }
        }else {
            synchronized (mirror){
                System.out.println(this.girlName + "Got the lock of the mirror");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            synchronized (lipStick){
                System.out.println(this.girlName + "Got the lock of lipstick");
            }
        }
    }
}

Lock lock

  • JDK5.0 has provided a more powerful thread synchronization mechanism -- synchronization is achieved by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects to act as

  • java.util.concurrent.locks.LOCK interface is a tool that controls multiple threads to access shared resources. Lock provides exclusive access to shared resources. Only one thread can lock the lock object at a time. Threads should obtain the lock object before accessing shared resources

  • ReentrantLock class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can explicitly add and release locks.

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //Test Lock
    public class TestLock {
    
        public static void main(String[] args) {
            TestLock2 testLock2 = new TestLock2();
            new Thread(testLock2).start();
            new Thread(testLock2).start();
            new Thread(testLock2).start();
        }
    }
    
    class TestLock2 implements Runnable{
    
        int ticketNums = 10;
        //Define lock lock
        private final ReentrantLock lock = new ReentrantLock();
        @Override
        public void run() {
            while (true){
    
                try{
                    lock.lock();
                    if (ticketNums>0){
                        System.out.println(ticketNums--);
                    }else {
                        break;
                    }
    
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }finally {
                    lock.unlock();
                }
    
            }
        }
    }
    

Production consumer model

Application scenario: producer and consumer issues

  • Assuming that only one product can be stored in the warehouse, the producer will put the produced products into the warehouse, and the consumer will take away the products in the warehouse for consumption.
  • If there is no product in the warehouse, the producer will put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer.
  • If there is a product in the warehouse, the consumer can take the product away for consumption, otherwise stop consumption and wait until the product is put into the warehouse again.

This is a problem of thread synchronization. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other.

  • For producers, before producing products, they should inform consumers to wait, and after producing products, they need to inform consumers to consume immediately

  • For consumers, after consumption, they should inform producers that they have finished consumption and need to produce new products for consumption.

  • In the production and consumer problems, synchronized is not enough

    • synchronized can prevent concurrent updating of the same shared resource and realize synchronization
    • synchronized cannot be used for message passing (Communication) between different threads
  • Java provides several methods to solve the communication problem between threads

    Method nameeffect
    wait()It means that the thread waits until other threads notify it. Unlike sleep, it will release the lock
    wait(long timeout)Specifies the number of milliseconds to wait
    notify()Wake up a waiting thread
    notifyAll()Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first

    All methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise an exception IIIegalMonitorStateException will be thrown

Concurrent collaboration model "producer / consumer model" -- > management method

  • Producer: the module responsible for production data (may be method, object, thread, process)

  • Consumer: module responsible for processing data (may be method, object, thread, process)

  • Buffer: consumers cannot directly use the data of producers. There is a "buffer" between them“

    The producer puts the produced data into the buffer, and the consumer takes out the data from the buffer

    //Test: producer consumer model -- > using buffer solution: pipe process method
    
    //Producer, consumer, product, buffer
    public class TestPC {
        public static void main(String[] args) {
            SynContainer container = new SynContainer();//Create buffer object
    
            new Productor(container).start();
            new Consumer(container).start();
        }
    
    }
    
    //producer
    class Productor extends Thread{
        SynContainer synContainer;
        public Productor(SynContainer synContainer){
            this.synContainer = synContainer;
        }
    
        @Override
        public void run() {
            for (int i = 1; i <= 100; i++) {
                Chicken chicken = new Chicken(i);
                synContainer.push(chicken);//Put in buffer
                System.out.println("Produced the second" + i + "Chicken");
            }
        }
    }
    
    //consumer
    class Consumer extends Thread{
        SynContainer synContainer;
        public Consumer(SynContainer synContainer){
            this.synContainer = synContainer;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                Chicken pop = synContainer.pop();
                System.out.println("Consumed the second" + pop.foodId + "Chicken");
                try {
                    Thread.sleep(300);//Control the time to prevent consumption before production
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    //product
    class Chicken{
        int foodId;
    
        public Chicken(int foodId) {
            this.foodId = foodId;
        }
    }
    
    //buffer
    class SynContainer{
        Chicken[] chickens = new Chicken[10];//Buffer size, type is access product
        int count = 0;//Buffer counter
    
        //Producers put in products
        public synchronized void push(Chicken chicken){
            //If the container is full, inform the consumer to consume
            if (count == chickens.length-1){
                //Inform consumers of consumption Producer waiting
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            //If it is not full, we need to throw in the product
            chickens[count] = chicken;
            count++;
    
            //Consumers can be informed of consumption
            this.notifyAll();
        }
    
        //Consumer products
        public synchronized Chicken pop(){
            //If the container is empty, stop consumption
            if (count ==0){
                //Consumers wait, producers produce
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //If you can consume
            count--;
            Chicken chicken = chickens[count];
    
            //After eating, inform the producer to produce
            this.notifyAll();
            return chicken;
        }
    
    }
    

Concurrent collaboration model "producer / consumer model" -- > semaphore method

//Producer, consumer mode -- > semaphore method
//Using flag bit control
//Performer, viewer, program
public class TestPC2 {
    public static void main(String[] args) {
        Tv tv = new Tv();
        new Player(tv).start();
        new Watcher(tv).start();
    }

}
//performer
class Player extends Thread{
    Tv tv;
    public Player(Tv tv){
        this.tv = tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i%2 == 0){
                this.tv.Programe("Action blockbuster");
            }else {
                this.tv.Programe("Love action blockbuster");
            }
        }
    }
}
//Viewer
class Watcher extends Thread{
    Tv tv;
    public Watcher(Tv tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for(int i=0;i<10;i++){
            this.tv.Watch();
        }
    }
}

//Products -- programs
class Tv{
    //The performer performs and the viewer waits
    //The audience watched and the actors waited
    String programme;//program
    boolean flag = true;



    //perform
    public synchronized void Programe(String programme){

            if (!flag){
                //Actor waiting
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        System.out.println("The actors performed:" + programme);
        //Inform the audience to watch
        this.flag = !this.flag;
        this.notifyAll();//Notification wake-up
        this.programme = programme;
    }

    //Watch the program
    public synchronized void Watch(){
            if (flag){
                try {
                    this.wait();//wait for
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("The audience watched:" + programme);
            //Inform the actors to perform
            this.notifyAll();
            this.flag = !this.flag;

    }
}

Thread pool

Use thread pool

Background: resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance.

Idea: create many threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after using them. It can avoid frequent creation, destruction and reuse.

Benefits: increased responsiveness

Reduce resource consumption

Easy thread management

corePoolSize: the size of the core pool

maximumPoolSize: maximum number of threads

keepAliveTime: when a thread has no task, how long does it last at most and then it will terminate

JDK 5.0 provides thread pool related API s: ExecutorService and Executors

ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor

void execute(Runnable command): executes a task / command without a return value. It is generally used to execute Runnable

Future submit (Callable task): when a task is executed and there is a return value, it usually executes Callable

void shutdown(): closes the connection pool

Executors: tool class and factory class of thread pool, which are used to create and return different types of thread pools

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//Test thread pool
public class TestPool {
    public static void main(String[] args) {
        //Create service and thread pool
        //newFixedThreadPool
        ExecutorService service = Executors.newFixedThreadPool(10);

        //implement
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //Close link
        service.shutdown();
    }

}
class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

Keywords: Java Back-end

Added by vinoindiamca on Tue, 01 Mar 2022 13:21:07 +0200