Java learning - Day08: multithreading

Posted by dineshthakur on Tue, 08 Feb 2022 04:39:18 +0100

1. Thread introduction

Multitasking: it seems that multiple tasks are doing at the same time. In fact, only one thing is done at the same time. Switching will soon lead to more things at the same time.

Multithreading: multiple lines do multiple things at the same time, multiple execution paths, and the main thread and sub thread execute alternately in parallel.

Program: a program is an ordered collection of instructions and data. It has no running meaning and is a static concept.

Process: it is a process of executing a program. It is a dynamic concept. It is the unit of system resource allocation.

Thread: a process can contain multiple threads. Thread is the unit of CPU scheduling and execution.

[note]: many multithreads are simulated. Real multithreading refers to having multiple CPUs, i.e. multiple cores, such as servers. If it is a simulated multithreading, that is, in the case of one CPU, the CPU can only execute one code at the same time point. Because the switching is fast, there is the illusion of simultaneous execution.

2. Thread creation*

Three creation methods: Thread (class) (key) Runnable (Interface) (key) Callable (Interface) (understand)

2.1 inherit Thread class

package study.javaSaenior.thread.demo01;

/**
 * Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread
 * Summary: when the thread is started, the computer does not necessarily execute it immediately, but it is scheduled by the CPU.
 * @author zhengxu
 * @create 2021-05-23 10:07
 */

//1. Inherit Thread class
public class TestThread1 extends Thread{

    //2. Rewrite the run() method
    @Override
    public void run() {
        //run method body
        for (int i = 0; i < 20; i++) {
            System.out.println("I'm looking at the code-------"+i);
        }
    }

    public static void main(String[] args) {
        //main thread

        //3. Create a thread object
        TestThread1 testThread1=new TestThread1();

        //4. Call the start() method to start the thread
        testThread1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("I'm learning multithreading--------"+i);
        }
    }
}

Operation results:
I'm learning multithreading--------0
 I'm looking at the code-------0
 I'm looking at the code-------1
 I'm learning multithreading--------1
 I'm learning multithreading--------2
 I'm learning multithreading--------3
 I'm learning multithreading--------4
 I'm looking at the code-------2

Case: online map download

import java.net.URL;

/**
 * Practice Thread to realize multi-threaded synchronous downloading of pictures
 * @author zhengxu
 * @create 2021-05-23 10:22
 */
public class TestThread2 extends Thread{

    private String url;//Network picture address
    private String name;//Saved file name

    public TestThread2(String url,String name){
        this.url=url;
        this.name=name;
    }

    //Download the execution body of the picture
    @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) {
        TestThread2 t1=new TestThread2("https://pics5.baidu.com/feed/f636afc379310a55ebfb2465fee3c9a1802610f6.jpeg?token=a360db8d557254f145f763044be748fa","1.jpg");
        TestThread2 t2=new TestThread2("https://pics1.baidu.com/feed/03087bf40ad162d986bd5b4f0a5b23e48b13cd9a.jpeg?token=a97dba301dd813678ae8d990093ae4cf","2.jpg");
        TestThread2 t3=new TestThread2("https://pics6.baidu.com/feed/38dbb6fd5266d0164e71448c8aaf5e0f34fa35b2.jpeg?token=fb0a64bbb1beae0a91826614da4ab8e0","3.jpg");

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

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 There is a problem with the method");
        }
    }
}

2.2 implementation of Runnable interface

package study.javaSaenior.thread.demo01;

/**
 * Thread creation mode 2: implement the Runnable interface and rewrite the run() method. The execution thread needs to throw into the runnnable interface implementation class and call the start() method
 * @author zhengxu
 * @create 2021-05-24 9:06
 */
public class TestThread3 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I'm looking at the code---"+i);
        }
    }

    public static void main(String[] args) {
        //Create the implementation class object of runnable interface
        TestThread3 testThread3=new TestThread3();
        //Create a thread object and start the thread agent through the thread object
//        Thread thread = new Thread(testThread3);
//        thread.start();
        new Thread(testThread3).start();

        for (int i = 0; i < 100; i++) {
            System.out.println("I'm learning multithreading--"+i);
        }
    }
}

[summary]

  • Inherit Thread class

    • The subclass inherits the Thread class and has the ability of multithreading
    • Start thread: subclass object start();
    • Not recommended: avoid the limitation of OOP single inheritance
  • Implement Runnable interface

    • The implementation interface Runnable has multithreading capability
    • Start Thread: pass in the target object + Thread object 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.

2.3 implement Callable interface (just understand)

package study.javaSaenior.thread.demo02;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
 * Create multithreading method 3: implement Callable interface (just understand)
 * 1.To implement the Callable interface, the return value type is required
 * 2.When overriding 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 < Boolean > result = Ser submit(t1);
 * 6.Get result: Boolean R1 = result1 get()
 * 7.Shut down the service: Ser shutdownNow()
 * 
 * Callable Benefits:
 * 1.You can define the return value
 * 2.Exceptions can be thrown
 * @author zhengxu
 * @create 2021-05-24 10:01
 */
public class TestCallable implements Callable {
    private String url;//Network picture address
    private String name;//Saved file name

    public TestCallable(String url,String name){
        this.url=url;
        this.name=name;
    }

    //Download the execution body of the picture
    @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 {
        TestCallable t1=new TestCallable("https://pics5.baidu.com/feed/f636afc379310a55ebfb2465fee3c9a1802610f6.jpeg?token=a360db8d557254f145f763044be748fa","1.jpg");
        TestCallable t2=new TestCallable("https://pics1.baidu.com/feed/03087bf40ad162d986bd5b4f0a5b23e48b13cd9a.jpeg?token=a97dba301dd813678ae8d990093ae4cf","2.jpg");
        TestCallable t3=new TestCallable("https://pics6.baidu.com/feed/38dbb6fd5266d0164e71448c8aaf5e0f34fa35b2.jpeg?token=fb0a64bbb1beae0a91826614da4ab8e0","3.jpg");

        //Create execution service:
        ExecutorService ser= Executors.newFixedThreadPool(3);
        //Submit for execution:
        Future<Boolean> r1=ser.submit(t1);
        Future<Boolean> r2=ser.submit(t2);
        Future<Boolean> r3=ser.submit(t3);
        //Get results:
        boolean rs1=r1.get();
        boolean rs2=r2.get();
        boolean rs3=r3.get();
        //Shut down service:
        ser.shutdownNow();
    }
}

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 There is a problem with the method");
        }
    }
}

3. Learn about concurrency

package study.javaSaenior.thread.demo01;

/**
 * Multiple threads operate on an object at the same time
 * Example: train ticket sale
 * 
 * Problems found: when multiple threads operate on the same resource, the thread is unsafe and the data is disordered.
 * @author zhengxu
 * @create 2021-05-24 9:22
 */
public class TestThread4 implements Runnable {

    private int ticket=10;

    @Override
    public void run() {
        while(true){
            if(ticket<=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticket--+"Tickets");
        }
    }

    public static void main(String[] args) {
        TestThread4 testThread4=new TestThread4();

        new Thread(testThread4,"Xiao Ming").start();
        new Thread(testThread4,"teacher").start();
        new Thread(testThread4,"cattle").start();
    }

}

Case: Tortoise and rabbit Race race Race race

package study.javaSaenior.thread.demo01;

/**
 * Case: Tortoise rabbit race
 * 1.First take a distance from the track, and then get closer and closer to the finish line
 * 2.Judge whether the game is over
 * 3.Print out the winner
 * 4.The tortoise and rabbit race began
 * 5.In the story, the tortoise wins and the rabbit needs to sleep, so let's simulate the rabbit to sleep
 * 6.Finally, the tortoise won the game
 * @author zhengxu
 * @create 2021-05-24 9:40
 */
public class Race implements Runnable{
    //winner
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //Simulated rabbit sleep
            if(Thread.currentThread().getName()=="rabbit"){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //Judge whether the game is over
            boolean flag=gameOver(i);
            //Stop the program if the game is over
            if(flag==true){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"Run away"+i+"step");
        }
    }

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

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

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

4. Static proxy mode

package study.javaSaenior.thread.demo02;

/**
 * Summary of static proxy mode:
 * 1.Both real objects and proxy objects should implement the same interface
 * 2.The proxy object should represent the real role
 * Benefits:
 * 1.Proxy objects can do many things that real objects cannot do
 * 2.Real objects can focus on doing their own things.
 * @author zhengxu
 * @create 2021-05-24 10:32
 */
public class StaticProxy {
    public static void main(String[] args) {

        You you=new You();//Are you getting married
        
        //Analogy two implementation principles, very similar
        //Thread is equivalent to a proxy object, and the runnable interface in parentheses is equivalent to a real object
        new Thread( ()-> System.out.println("I love you!")).start();
        
        new WeddingCompany(you).HappyMarry();
        

    }
}

interface Marry{
    //Four great happenings in the world
    void HappyMarry();

}

//Real role
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("I'm getting married. I'm so happy!");
    }
}

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

    //Who to represent -- > real target role
    private Marry target;

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

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//This is the real object
        after();
    }

    private void before() {
        System.out.println("Before marriage, set up the scene");
    }

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

5.Lambda expression

Why use lambda expressions

  • Avoid too many anonymous inner class definitions
  • It can make your code look neat
  • Removed a pile of meaningless code, leaving only the core logic

Understanding the Functional Interface is the key to learning java 8 lambda expressions

Definition of functional interface:

  • Any interface that contains only one abstract method is a functional interface.
public interface Runnable{
    public abstract void run();
}
  • For functional interfaces, we can create objects of the interface through lambda expressions.
package study.javaSaenior.thread.demo03;

/**
 * Deduce the evolution of lambda expression
 * @author zhengxu
 * @create 2021-05-24 19:48
 */
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: if there is no class name, you must use the interface or parent class
        like=new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();

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

    }
}

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

//2. Implementation class
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("I like lambda1");
    }
}
package study.javaSaenior.thread.demo03;

/**
 * lambda expression with parameters
 * Summary:
 *  1.lambda The expression can only be simplified into one line if there is only one line of code. If there are multiple lines, wrap {} with code blocks
 *  2.The premise is that the interface is a functional interface (there is only one interface in the interface)
 *  3.The parameter type can also be removed from multiple parameters. If you want to remove them, you must add parentheses (a, b) - > code block
 * @author zhengxu
 * @create 2021-05-24 20:07
 */
public class TestLambda02 {
    public static void main(String[] args) {
        ILove love=new Love();
        love.love(1);

        //lambda simplification 1
        love=(int a)->{System.out.println("I love you"+a);};
        //lambda simplification 2: parameter types
        love=(a)->{System.out.println("I love you"+a);};
        //lambda 3: simplify parentheses
        love=a->{System.out.println("I love you"+a);};
        //lambda 4: simplify curly braces
        love=a-> System.out.println("I love you"+a);
        love.love(2);
    }
}

interface ILove{
    void love(int a);
}

class Love implements ILove{
    @Override
    public void love(int a) {
        System.out.println("I love you"+a);
    }
}

Completely simplified code

package study.javaSaenior.thread.demo03;

public class TestLambda02 {
    public static void main(String[] args) {
        ILove love=a-> System.out.println("I love you"+a);
        love.love(2);
    }
}

interface ILove{
    void love(int a);
}

6. Thread status

[the external chain image transfer fails. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-7zrtlyx1-1622090764969) (C: \ users \ Zhengxu \ appdata \ roaming \ typora user images \ image-20210521165815921. PNG)]

6.1 common methods of multithreading

  • **void start() 😗* Start the thread and execute the run() method of the object

  • **run() 😗* The operation that a thread performs when it is scheduled

  • **String getName() 😗* Returns the name of the thread

  • **viod setName(String name) 😗* Set the thread name

  • **static Thread currentThread() 😗* Returns the current thread. When this is in a subclass, it is usually used for the main thread and Runnable implementation class

  • **static void yield() 😗* Thread concession. Pause the currently running thread and give the opportunity to the thread with the same or higher priority

  • **join() 😗* When the join () method of other threads is invoked in a program execution stream, the calling thread will be blocked until the join thread added by the join () method is executed.

  • static void sleep(long millis): (specified time: milliseconds). Make the current active thread give up control over the CPU within the specified time period, and other threads have the opportunity to be executed. When the time comes, queue up again.

    Throw an InterruptionException exception.

  • **stop() 😗* Force the end of thread life cycle. It is not recommended.

  • **boolean isAlive: * * returns boolean to judge whether the thread is still alive.

  • **suspend() 😗* Suspended, not recommended.

  • **resume() 😗* End pending status, not recommended.

  • **notify()/notifyAll() 😗* awaken

6.2 stopping threads

  • The stop(), destroy() method provided by JDK is not recommended. [abandoned]
  • It is recommended to let the thread stop by itself
  • It is recommended to use a flag bit to terminate the variable. When flag=false, the thread is terminated.
package study.javaSaenior.thread.demo03;

/**
 * Test stop
 * 1.It is recommended that threads stop normally - > utilization times, and do not loop
 * 2.It is recommended to use flag bit - > set a flag bit
 * 3.Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK
 * @author zhengxu
 * @create 2021-05-24 20:54
 */
public class TestStop implements Runnable{
    //1. Define the ID used by the thread body in the thread
    private Boolean flag=true;

    @Override
    public void run(){
        int i=0;
        //2. The thread body uses this ID
        while(flag){
            System.out.println("run....Thread"+i++);
        }
    }
    //3. Provide external method change identification
    public void stop(){
        this.flag=false;
    }

    public static void main(String[] args) {
        TestStop testStop=new TestStop();
        new Thread(testStop).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if(i==900){
                //Call the stop method to switch the flag bit and stop the thread
                testStop.stop();
                System.out.println("The thread stopped");
            }
        }
    }
}

6.3 thread hibernation

package study.javaSaenior.thread.demo03;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Analog countdown
 * 1.sleep(Time) specifies the number of milliseconds the current thread is blocking
 * 2.sleep There is an exception InterruptedException
 * 3.sleep When the time reaches, the thread enters the ready state
 * 4.sleep It can simulate network delay, countdown, etc.
 * 5.Every object has a lock, and sleep will not release the lock.
 * @author zhengxu
 * @create 2021-05-24 21:39
 */
public class TestSleep02 {

    public static void main(String[] args) {
//        try {
//            tenDown();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        //Print current system time
        Date startTime=new Date(System.currentTimeMillis());

        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime=new Date(System.currentTimeMillis());//Update current time
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //Analog countdown
    public static void tenDown() throws InterruptedException {
        int num=10;

        while(true){

            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0){
                break;
            }
        }
    }
}

6.4 comity

  • Pause the current thread without blocking it
  • Change the thread from running state to ready state
  • Let the CPU reschedule, comity is not necessarily successful! Look at CPU mood
package study.javaSaenior.thread.demo03;

/**
 * @author zhengxu
 * @create 2021-05-24 22:17
 */
public class TestYield {

    public static void main(String[] args) {
        MyYield yield=new MyYield();

        new Thread(yield,"a").start();
        new Thread(yield,"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");
    }
}

6.5 thread enforcement

  • join merge threads. After this thread completes execution, execute other threads. Other threads are blocked.
  • It can be imagined as queue jumping and VIP channel.
package study.javaSaenior.thread.demo03;

/**
 * Test join method: imagine jumping in line
 * @author zhengxu
 * @create 2021-05-24 22:23
 */
public class TestJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <=1000; i++) {
            System.out.println("thread  VIP coming"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {

        //Start our thread
        TestJoin testJoin=new TestJoin();
        Thread thread=new Thread(testJoin);
        thread.start();

        //Main thread
        for (int i = 0; i < 1000; i++) {
            if(i==200){
               thread.join();//Jump in line
            }
            System.out.println("main"+i);
        }

    }
}

6.6 thread state observation

  • Thread.State

    Thread status. A thread can be in one of the following states

    • 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

      Threads that are blocked waiting for a monitor lock are in this state

    • WAITING

      A 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 perform the action for the specified waiting time is in this state

    • TERMINATED

      The exited thread is in this state

A thread can be in a state at a given point in time. These states are virtual machine states that do not reflect any operating system thread state.

package study.javaSaenior.thread.demo03;

/**
 * Observe the status of the test thread
 * @author zhengxu
 * @create 2021-05-24 23:02
 */
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("///");
        });

        //Observation state
        Thread.State state=thread.getState();
        System.out.println(state);//NEW
        //Observe after startup
        thread.start();
        state=thread.getState();
        System.out.println(state);//RUNABLE

        while (state!=Thread.State.TERMINATED){//The thread does not terminate as long as it is in the output state
            Thread.sleep(100);
            state=thread.getState();//Update thread status
            System.out.println(state);
        }
    }
}

7. 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)
package study.javaSenior.thread.demo03;

/**
 * Test thread priority
 * Conclusion: low priority only means that the probability of obtaining scheduling is low, not that it will not be called if the priority is low, which depends on the scheduling of CPU.
 * @author zhengxu
 * @create 2021-05-26 8:37
 */
public class TestPriority {
    public static void main(String[] args) {
        //The main thread has the default priority
        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);

        //Set priority before starting
        t1.setPriority(1);
        t2.setPriority(3);
        t3.setPriority(Thread.MAX_PRIORITY);//10
        t1.start();
        t2.start();
        t3.start();
    }
}

class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
    }
}

8. Daemon thread

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
  • Such as: recording operation logs in the background, monitoring memory, garbage collection, etc
package study.javaSenior.thread.demo03;

/**
 * Test daemon thread: God guards you
 * @author zhengxu
 * @create 2021-05-26 8:51
 */
public class TestDaemon {

    public static void main(String[] args) {
        God god=new God();
        You you=new You();

        Thread thread=new Thread(god);
        thread.setDaemon(true);//The default is false, which means that it is a user thread. Normal threads are user threads

        thread.start();//God Guardian thread qid

        new Thread(you).start();//Your user thread starts

    }

}

//lord
class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("God bless you");
        }
    }
}

//you
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("Have you been happy all your life");
        }
        System.out.println("======goodbye! world!=======");
    }
}

9. Thread synchronization*

Multiple threads operate on the same resource

Concurrency: the same object is operated by multiple threads at the same time

Thread synchronization is actually 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 use it, and then use it for the next thread. Solve the problem of thread insecurity

Forming conditions: queue + lock

  • Because multiple threads of the same process share the same storage space, it brings convenience and access conflict. In order to ensure the correctness of data being accessed in the method, the lock mechanism 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:
    • A thread holding a lock will cause other threads that need the lock to be suspended
    • In multi-threaded 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

9.1 three unsafe cases - buying tickets

package study.javaSenior.thread.syn;

/**
 * Three unsafe cases: unsafe ticket buying
 * @author zhengxu
 * @create 2021-05-26 9:18
 */
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station=new BuyTicket();

        new Thread(station,"Forced me").start();
        new Thread(station,"Damn you").start();
        new Thread(station,"Damn scalpers").start();
    }
}

class BuyTicket implements Runnable{
    //ticket
    private int ticketNums = 10;
    boolean flag=true;//External stop mode
    @Override
    public void run() {
        //Buy a ticket
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        //Judge whether there are tickets
        if(ticketNums<=0){
            flag=false;
            return;
        }
        //Analog delay
        Thread.sleep(100);
        //Buy a ticket
        System.out.println(Thread.currentThread().getName()+"Bought the second"+ticketNums--+"Tickets");
    }
}
//There will be - 1 votes.

9.2 three unsafe cases - Banks

package study.javaSenior.thread.syn;

/**
 * Unsafe withdrawal: two people withdraw money
 * @author zhengxu
 * @create 2021-05-26 10:06
 */
public class UnsafeBank {
    public static void main(String[] args) {
        //account
        Account account=new Account(100,"Marriage fund");

        Drawing you=new Drawing(account,50,"you");
        Drawing girlFriend=new Drawing(account,100,"girl friend");

        you.start();
        girlFriend.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;//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() {
        //Judge whether there is money
        if(account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw");
            return;
        }

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

        //Card balance = balance - the money you withdraw
        account.money=account.money-drawingMoney;
        //The money in your hand
        nowMoney=nowMoney+drawingMoney;

        System.out.println(account.name+"The balance is:"+account.money);
        //Because of inheritance: this getName()=Thread. currentThread(). getName()
        System.out.println(this.getName()+"Money in hand:"+nowMoney);
    }
}
//Operation results:
//Marriage fund balance: 50
//Marriage fund balance: 50
//Money in your hand: 50
//Money in girlfriend's hand: 100

9.3 three unsafe cases - Collection

package study.javaSenior.thread.syn;

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

/**
 * Thread unsafe collection
 * Thread Runtime: when two threads run at the same time, the array is generated to the same location and covered.
 * @author zhengxu
 * @create 2021-05-26 17:06
 */
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();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
//Operation results:
//9998

9.4 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 and release the lock until the method returns. Only the blocked thread can obtain the lock and continue to execute.
  • **Defect: * * declaring a large method synchronized will affect efficiency. Only the contents that need to be modified in the method need to be locked. Too many locks will waste resources.

The duplicate ticket problem in the ticket selling example is a typical thread safety problem.

/**
 * Example 2: create three windows with a total of 100 votes, using the way to implement the Runnale interface
 *
 * 1.Problem: there are problems of duplicate tickets and wrong tickets in the process of buying tickets - > there is a thread safety problem
 * 2.Cause of the problem: when a thread operates the thread and the operation has not been completed, other threads participate and operate the ticket.
 * 3.Solution: when a thread is operating the ticket, other threads cannot participate. Only when the current thread completes the operation can other threads participate.
 *   Even if the current thread is blocked, it cannot be changed.
 * 4.Java In, we solve the problem of thread safety through synchronization mechanism.
 *
 *    Method 1: synchronize code blocks
 *         synchronized(Synchronization monitor){
 *              //Code to be synchronized
 *         }
 *       Description: 1 The code that operates the shared data is the code that needs to be synchronized. -- > Cannot contain more or less code
 *            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!!!!!! The monitor can be changed into static by inheriting Thread
 *            Add: in the way of implementing Runnable interface to create multithreading, you can consider using this as the synchronization monitor.
 *                 Using synchronous code block to solve the Thread safety problem of inheriting Thread class, you can turn obj into static to prevent the monitor from being not unique.
 *
 *    Method 2: synchronization method
 *       If the code that operates on shared data is completely declared in a method, we might as well declare this method synchronous.
 *       1.The synchronization method still involves the synchronization monitor, as long as we don't need to explicitly declare it.
 *		 2.The synchronization monitor of non static synchronization method is: this
 *		 3.The synchronization monitor of the static method is: the current class itself, XX class
 *
 * 5.The way of synchronization solves the problem of thread safety. - > benefit
 *   While operating the synchronization code, only one thread can participate and other threads wait. It is equivalent to a single threaded process with low efficiency shortcoming
 */
9.4.1 the synchronous code block method deals with the security problem of creating multithreads by Runnable interface
package study.javaSaenior.exercise;

class Window1 implements Runnable{

    private int ticket=100;//You don't need to use static, because only one Window1 is instantiated in main!!!!
    Object obj=new Object();//Here, three threads share a lock, and three locks are placed in run().

    @Override
    public void run() {
        while (true) {
            //synchronized(this) {
            //synchronized(window1.class) {
            synchronized(obj) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class WindowTest01 {

    public static void main(String[] args) {
        Window1 w=new Window1();

        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();

    }
}
9.4.2 the synchronous code block method deals with thread safety problems caused by inheriting the tree class
package study.javaSaenior.exercise;

/**
 * Use synchronous code blocks to solve the Thread safety problem of inheriting Thread class
 *
 * @author zhengxu
 * @create 2021-05-22 12:13
 */
class Window2 extends Thread{

    private static int ticket=100;
    private static Object obj=new Object();

    @Override
    public void run() {
        while(true){
            synchronized (obj) {//There will still be errors, because each of the following three windows has a lock, which can change obj into static!!!!!!!!!!!!!
                if (ticket > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + ":Ticket number:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

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

        Window2 w1=new Window2();
        Window2 w2=new Window2();
        Window2 w3=new Window2();

        w1.setName("Window 1");
        w2.setName("Window 2");
        w3.setName("Window 3");

        w1.start();
        w2.start();
        w3.start();

    }
}
9.4.3 the synchronization method deals with the thread safety problem of realizing Runnable
package study.javaSaenior.exercise;
//Extract the method and add the modifier synchronized
class Window4 implements Runnable{

    private int ticket=100;

    @Override
    public  void run() {
        while (true) {
            show();
        }
    }

    private synchronized void show(){ //Synchronization method: the default synchronization monitor is this
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket);
            ticket--;
        }
    }
}

public class WindowTest04 {

    public static void main(String[] args) {
        Window4 w=new Window4();

        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();

    }
}
9.4.4 the synchronization method handles the Thread safety problem of inheriting Thread class
package study.javaSaenior.exercise;

//Using synchronous methods to deal with Thread safety problems in the way of inheriting Thread class
class Window3 extends Thread{

    private static int ticket=100;

    @Override
    public void run() {
        while(true){
            show();
        }
    }

    //private synchronized void show() {/ / the synchronization monitor is this, but three threads corresponding to one lock are established. Error
    private static synchronized void show(){//Add a static, and the synchronization monitor is windows 4 class!!!!!!!
        if (ticket > 0) {

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket);
            ticket--;
        }
    }
}

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

        Window3 w1=new Window3();
        Window3 w2=new Window3();
        Window3 w3=new Window3();

        w1.setName("Window 1");
        w2.setName("Window 2");
        w3.setName("Window 3");

        w1.start();
        w2.start();
        w3.start();

    }
}

10. Thread deadlock

  • 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.

    After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue

  • resolvent

    Special algorithms and principles

    Minimize the definition of synchronization resources

    Try to avoid nested synchronization

package study.javaSaenior.thread;

/**
 * Demonstrate thread deadlock
 * Thread 1 is waiting, holding s1 is waiting for s2, and thread 2 is holding s2 and waiting for s1. A deadlock occurs
 * @author zhengxu
 * @create 2021-05-22 20:55
 */
public class ThreadTest02 {
    public static void main(String[] args) {

        StringBuffer s1=new StringBuffer();
        StringBuffer s2=new StringBuffer();

        new Thread(){
            @Override
            public void run() {
                synchronized (s1){
                    s1.append("a");
                    s2.append("1");

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

                    synchronized (s2){
                        s1.append("b");
                        s2.append("2");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();

        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();
    }
}

11.Lock lock

  • From jdk5 Since 0, Java has provided a more powerful thread synchronization mechanism -- realizing synchronization by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects 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. The lock object should be alive before the thread starts to access shared resources.
  • ReentrantLock (reentrant Lock) 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.
package study.javaSenior.thread.gaoji;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Test Lock
 * @author zhengxu
 * @create 2021-05-27 8:33
 */
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 ticketNumbers=10;

    //Define reentrant Lock
    private  final ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                lock.lock();//Lock
                if (ticketNumbers > 0) {
                    System.out.println(Thread.currentThread().getName()+":"+ticketNumbers--);
                }else{
                    break;
                }
            }finally {
                //Unlock
                lock.unlock();
            }
        }
    }
}
  • Lock is an explicit lock (manually open and close the lock, don't forget to close the lock). synchronized is an implicit lock, which is automatically released out of the scope.

  • Lock only has code block lock, and synchronized has code block lock and method lock.

  • Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better scalability (providing more subclasses).

  • Use priority:

    Lock > synchronization code block (has entered the method body and allocated corresponding resources) > synchronization method (outside the method body)

12. Thread communication

Producer consumer model

Application scenario: producer and consumer issues

  • Suppose that only one product can be stored in the warehouse, the producer puts the produced products into the warehouse, and the consumer takes the products from 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 thread synchronization problem. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other.

Java provides a way to solve the communication problem between threads

  • **wait(): * * indicates that the thread waits until other threads notify it. Unlike sleep, which releases the lock.
  • **wait(long time) 😗* Wait for the specified number of milliseconds
  • **notify() 😗* Wake up a waiting thread
  • **notifyAll: * * wake up all threads calling the wait() method on the same object, and the threads with higher priority are scheduled first.

[note]: all methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise an exception lllegalMonitorStateException will be thrown

12.1 solution 1: pipe pass method

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

package study.javaSenior.thread.gaoji;

/**
 * Producer buffer solution
 * Producer, consumer, product, buffer
 * @author zhengxu
 * @create 2021-05-27 10:13
 */
public class TestPC {
    public static void main(String[] args) {
       SynContainer container=new SynContainer();

       new Producer(container).start();
       new Consumer(container).start();
    }
}

//producer
class Producer extends Thread{
    SynContainer container;
    public Producer(SynContainer container){
        this.container=container;
    }

    //production

    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            container.push(new Chicken(i));
            System.out.println("Produced the second"+i+"Chicken");
        }
    }
}

//consumer
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Consumed the second"+container.pop().id+"Chicken");
        }
    }
}

//product
class Chicken{
    int id;  //Product number

    public Chicken(int id) {
        this.id = id;
    }
}

//buffer
class SynContainer{

    //A container size is required
    Chicken[] chickens=new Chicken[10];
    //Container counter
    int count=0;

    //Producers put in products
    public synchronized void push(Chicken chicken){
        //If the container is full, it needs to wait for consumers to consume
        if(count==chickens.length-1){
            //Inform consumers and producers to wait
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            //If it is not full, throw it into the product
            count++;
            chickens[count]=chicken;
        }

        //Consumers can be informed of consumption
        this.notifyAll();

    }


    //Consumer products
    public synchronized Chicken pop(){

        //Judge whether it can be consumed
        if(count==0){
            //Consumers wait for producers to produce
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //If you can consume
        Chicken chicken=chickens[count];
        count--;
        //After eating, inform the producer to produce
        this.notifyAll();
        return chicken;
    }
}

12.2 solution 2: signal lamp method

package study.javaSenior.thread.gaoji;

/**
 * Test producer consumer problem 2: signal lamp method, flag bit solution
 * @author zhengxu
 * @create 2021-05-27 11:26
 */
public class TestPC2 {
    public static void main(String[] args) {
        Tv tv=new Tv();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//Producer - > actor
class Player extends Thread{
    Tv tv;
    public Player(Tv tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0){
                this.tv.play("Happy camp broadcast");
            }else{
                this.tv.play("Jitter: tiktok: record the good life");
            }
        }
    }
}

//Consumer - > audience
class Watcher extends Thread{
    Tv tv;
    public Watcher(Tv tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            tv.watch();
        }
    }
}

//Products - > Programs
class Tv{
    //The audience waited and the actors performed
    String voice;//A performance
    boolean flag=true;//true indicates the amount of visitors, and false indicates that they haven't come yet

    //perform
    public synchronized void play(String voice){
        if(!flag){
            try {
                this.wait();//The audience didn't come, waiting for the audience to come
                this.voice=voice;
                System.out.println("The actors performed:"+voice);//Wait for the end and start the performance
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //The audience came and began to perform
        this.flag=!this.flag;//At the end of the performance, the audience left
        this.notifyAll();//Remind the audience to come again
    }

    //watch
    public synchronized void watch(){
        if(flag){
            try {
                wait();//Waiting to watch
                System.out.println("The audience watched:"+voice);//Wait for the end and start watching
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //Inform the actors to perform
        this.flag=!this.flag;
        this.notifyAll();

    }
}

13. Thread pool

  • Background: often creating, destroying and using very large resources, such as threads in concurrency, has 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 and destruction and realize reuse. Similar to public transport in life.
  • Benefits:
    • Improved response speed (reduced time to create new threads)
    • Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)
    • Easy thread management (...)
      • corePoolSize: the size of the core pool
      • maximumPoolSize: maximum number of threads
      • keepAliveTime: the maximum time a thread can hold without a task before terminating.
package study.javaSenior.thread.gaoji;

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

/**
 * Test thread pool
 * @author zhengxu
 * @create 2021-05-27 12:30
 */
public class TestPool {
    public static void main(String[] args) {
        //1. Create service and thread pool
        //The newFixedThreadPool parameter is the thread pool size
        ExecutorService service=Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1=(ThreadPoolExecutor) service;
        //Set thread pool properties
        service1.setCorePoolSize(15);
        service1.setKeepAliveTime(100);
        
        //2. Execute the specified thread operation. You need to provide an object that implements the Runnable interface or the Callable interface implementation class
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());//Applicable to Runnable interface
        service.submit(new MyThread());//For Callable interface

        //3. Close the connection pool
        service.shutdown();
    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());

    }
}

Topics: Java