Java exceptions and threads

Java exceptions and threads

abnormal

Exception: refers to an abnormal situation during the execution of the program, which will eventually lead to the abnormal stop of the JVM. The exception mechanism actually helps us find problems in the program. The root class of the exception is java.lang.Throwable, which has two subclasses, java.lang.Error and java.lang.Exception. The usual exception refers to java.lang.Exception.

Throwable system:
Error: a serious error. An error that cannot be handled can only be avoided in advance, like a terminal disease.
Exception: indicates an exception. After an exception is generated, the programmer can correct it through code to make the program continue to run. It must be handled.

Common methods in Throwable:
public void printStackTrace(): print the details of the exception. It includes the type of exception, the reason for the exception, and the location of the exception. printStackTrace must be used in the development and debugging stages.
public String getMessage(): get the reason for the exception. When prompted to the user, the error reason will be prompted.
public String toString(): get the exception type and exception description information (not required).

/*
    java.lang.Throwable:Class is a superclass for all errors or exceptions in the Java language.
        Exception:Compile time exceptions, problems in compiling (writing code) java programs
            RuntimeException:Run time exceptions, problems in the running process of java programs
            Exception is equivalent to a small problem in the program. Deal with the exception and the program can continue to execute
        Error:error
            An error is equivalent to an incurable problem in the program. The source code must be modified before the program can continue to execute
 */
public class DemoException {
    public static void main(String[] args) /*throws ParseException*/ {
        //Exception: compile time exception, which is a problem in compiling (writing code) java programs
        /*SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//Used to format the date
        Date date = null;
        try {
            date = sdf.parse("1999-0909");//Parse the Date in string format into Date format
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println(date);*/

        //RuntimeException: run-time exception, a problem that occurs during the running of a java program
        /*int[] arr = {1,2,3};
        //System.out.println(arr[0]);
        try {
            //Code with possible exceptions
            System.out.println(arr[3]);
        }catch(Exception e){
            //Exception handling logic
            System.out.println(e);
        }*/

        /*
            Error:error
            OutOfMemoryError: Java heap space
            Memory overflow error. The array created is too large and exceeds the memory allocated to the JVM
         */
        //int[] arr = new int[1024*1024*1024];
        //The code must be modified to create a smaller array
        int[] arr = new int[1024*1024];
        System.out.println("Subsequent code");
    }
}

throw exception

*
    throw keyword
    effect:
        have access to throw Keyword throws the specified exception in the specified method
    Use format:
        throw new xxxException("Cause of abnormality");
    be careful:
        1.throw Keywords must be written inside the method
        2.throw After keyword new The object must be Exception perhaps Exception Subclass object of
        3.throw Keyword throws the specified exception object,We have to deal with this exception object
            throw After the keyword is created RuntimeException Or RuntimeException Subclass object of,We don't have to deal with it,Default to JVM handle(Print exception object,Interrupt program)
            throw A compilation exception is created after the keyword(An error is reported when writing code),We have to deal with this exception,or throws,or try...catch
 */
public class DemoThrow {
    public static void main(String[] args) {
        //int[] arr = null;
        int[] arr = new int[3];
        int e = getElement(arr,3);
        System.out.println(e);
    }
    /*
        Defines a method to get the element at the specified index of the array
        Parameters:
            int[] arr
            int index
        In the future (work), we must first verify the validity of the parameters passed by the method
        If the parameter is illegal, we must throw an exception to inform the caller of the method that there is a problem with the passed parameter
        be careful:
            NullPointerException It is a runtime exception. We don't need to handle it. It is handed over to the JVM by default
            ArrayIndexOutOfBoundsException It is a runtime exception. We don't need to handle it. It is handed over to the JVM by default
     */
    public static int getElement(int[] arr,int index){
        /*
            We can verify the validity of the passed parameter array
            If the value of array arr is null
            Then we throw a null pointer exception and tell the caller of the method that "the value of the passed array is null"
         */
        if(arr == null){
            throw new NullPointerException("The value of the array passed is null");
        }

        /*
            We can verify the validity of the passed parameter index
            If the index range is not within the index range of the array
            Then we throw an array index out of bounds exception and tell the caller of the method that "the passed index exceeds the range of use of the array"
         */
        if(index<0 || index>arr.length-1){
            throw new ArrayIndexOutOfBoundsException("The index passed is out of range for the array");
        }

        int ele = arr[index];
        return ele;
    }
}

Object throws an exception

import java.util.Objects;

/*
    Objects Static methods in classes
    public static <T> T requireNonNull(T obj):View that the specified reference object is not null.
    Source code:
        public static <T> T requireNonNull(T obj) {
            if (obj == null)
                throw new NullPointerException();
            return obj;
        }
 */
public class DemoObjects {
    public static void main(String[] args) {
        method(null);
    }

    public static void method(Object obj){
        //Judge the validity of the passed parameters to determine whether they are null
        /*if(obj == null){
            throw new NullPointerException("The value of the object passed is null ');
        }*/

        //Objects.requireNonNull(obj);
        Objects.requireNonNull(obj,"The value of the object passed is null");
    }
}

Declare exception throws

import java.io.FileNotFoundException;
import java.io.IOException;

/*
    throws Keyword: the first method of exception handling, which is handed over to others for handling
    effect:
        When an exception object is thrown inside a method, we must deal with the exception object
        You can use the throws keyword to handle the exception object. The exception object declaration will be thrown to the caller of the method for processing (you will not handle it yourself, but others), and finally handed over to the JVM for processing -- > interrupt processing
    Use format: used in method declaration
        Modifier return value type method name (parameter list) throws aaaexcepton, bbbexcepton{
            throw new AAAExcepiton("Cause ");
            throw new BBBExcepiton("Cause ");
            ...
        }
     be careful:
        1.throws Keywords must be written at the method declaration
        2.throws The Exception declared after the keyword must be an Exception or a subclass of Exception
        3.If multiple exception objects are thrown inside the method, multiple exceptions must also be declared after throws
            If multiple exception objects thrown have a child parent relationship, you can directly declare the parent exception
        4.If we call a method that declares that an exception is thrown, we must handle the declared exception
            Or continue to use the throws declaration to throw it, give it to the caller of the method for processing, and finally give it to the JVM
            Or try...catch handle the exception yourself
 */
public class DemoThrows {
    /*
        FileNotFoundException extends IOException extends Excepiton
        If multiple exception objects thrown have a child parent relationship, you can directly declare the parent exception
     */
    //public static void main(String[] args) throws FileNotFoundException,IOException {
    //public static void main(String[] args) throws IOException {
    public static void main(String[] args) throws Exception {
        readFile("c:\\a.tx");

        System.out.println("Subsequent code");
    }

    /*
        Define a method to judge the legitimacy of the transmitted file path
        If the path is not "c:\a.txt", we will throw the file and tell the caller of the method that the exception object cannot be found
        be careful:
            FileNotFoundException It is a compilation exception. If a compilation exception is thrown, it must be handled
            You can use the throws declaration to throw FileNotFoundException, an exception object, for the caller of the method to handle
     */
    public static void readFile(String fileName) throws FileNotFoundException,IOException{
        if(!fileName.equals("c:\\a.txt")){
            throw new FileNotFoundException("The file path passed is not c:\\a.txt");
        }

        /*
            If the path passed is not at the end of. txt
            Then we throw an IO exception object to tell the caller of the method that the file suffix is wrong

         */
        if(!fileName.endsWith(".txt")){
            throw new IOException("The suffix of the file is incorrect");
        }

        System.out.println("There is no problem with the path,read file");
    }
}

Exception capture try... catch

import java.io.IOException;

/*
    try...catch:The second way of exception handling is to handle exceptions by yourself
    be careful:
        1.try Multiple exception objects may be thrown in, so you can use multiple catch es to handle these exception objects
        2.If an exception occurs in try, the exception handling logic in catch will be executed, the processing logic in catch will be executed, and the code after try...catch will continue to be executed
          If there is no exception in try, the exception handling logic in catch will not be executed, the code in try will be executed, and the code after try...catch will continue to be executed
 */
public class DemoTryCatch {
    public static void main(String[] args) {
        try{
            //Code that may cause exceptions
            readFile("d:\\a.tx");
            System.out.println("Resource release");
        }catch (IOException e){//catch defines exception variables to receive exception objects thrown in try
            //Exception handling logic, how to handle the exception object after the exception object
            //System.out.println("catch - the file suffix passed is not. txt");

            /*
                Throwable Class defines three exception handling methods
                 String getMessage() Returns a short description of this throwable.
                 String toString() Returns the detailed message string for this throwable.
                 void printStackTrace()  JVM This method is used by default to print exception objects. The printed exception information is the most comprehensive
             */
            //System.out.println(e.getMessage());// The suffix of the file is incorrect
            //System.out.println(e.toString());// Rewrite toString java.io.IOException of Object class: the suffix name of the file is incorrect
            //System.out.println(e);//java.io.IOException: the suffix of the file is incorrect

            /*
                java.io.IOException: The suffix of the file is incorrect
                    at com.itheima.demo02.Exception.Demo01TryCatch.readFile(Demo01TryCatch.java:55)
                    at com.itheima.demo02.Exception.Demo01TryCatch.main(Demo01TryCatch.java:27)
             */
            e.printStackTrace();
        }
        System.out.println("Subsequent code");
    }

    /*
       If the path passed is not at the end of. txt
       Then we throw an IO exception object to tell the caller of the method that the file suffix is wrong

    */
    public static void readFile(String fileName) throws IOException {

        if(!fileName.endsWith(".txt")){
            throw new IOException("The suffix of the file is incorrect");
        }

        System.out.println("There is no problem with the path,read file");
    }
}

Code block finally

/*
    finally Code block
     be careful:
        1.finally It cannot be used alone. It must be used with try
        2.finally It is generally used for resource release (resource recovery). No matter whether the program is abnormal or not, the resource should be released (IO) at last
 */
public class Demo02TryCatchFinally {
    public static void main(String[] args) {
        try {
            //Code that may generate exceptions
            readFile("c:\\a.tx");
        } catch (IOException e) {
            //Exception handling logic
            e.printStackTrace();
        } finally {
            //Whether an exception occurs or not, it is executed
            System.out.println("Resource release");
        }
    }

    /*
       If the path passed is not at the end of. txt
       Then we throw an IO exception object to tell the caller of the method that the file suffix is wrong

    */
    public static void readFile(String fileName) throws IOException {

        if(!fileName.endsWith(".txt")){
            throw new IOException("The suffix of the file is incorrect");
        }

        System.out.println("There is no problem with the path,read file");
    }
}

Exception in class

/*
    Exception of child parent class:
        - If the parent class throws multiple exceptions, when overriding the parent class method, the child class throws the same exception as the parent class, or the child of the parent class exception, or does not throw an exception.
        - The parent class method does not throw an exception, and the child class cannot throw an exception when overriding the parent class method. At this time, the subclass generates the exception, which can only be caught and processed, and cannot be declared and thrown
    be careful:
        When the parent class is abnormal, the child class is abnormal
 */
public class Fu {
    public void show01() throws NullPointerException,ClassCastException{}
    public void show02() throws IndexOutOfBoundsException{}
    public void show03() throws IndexOutOfBoundsException{}
    public void show04() throws Exception {}
}

class Zi extends Fu{
    //When a subclass overrides a parent class method, it throws the same exception as the parent class
    public void show01() throws NullPointerException,ClassCastException{}
    //A subclass that throws a parent exception when overriding a parent method
    public void show02() throws ArrayIndexOutOfBoundsException{}
    //Subclasses do not throw exceptions when overriding parent methods
    public void show03() {}

    /*
        The parent class method does not throw an exception, and the child class cannot throw an exception when overriding the parent class method.

     */
    //public void show04() throws Exception{}

    //At this time, the subclass generates the exception, which can only be caught and processed, and cannot be declared and thrown
    public void show04()  {
        try {
            throw  new Exception("Compile time exception");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


Multithreading

Concurrency and parallelism
Concurrency: two or more events occur in the same time period.
Parallel: two or more events occur at the same time (at the same time)

Process: refers to an application running in memory. Each process has an independent memory space. An application can run multiple processes at the same time; Process is also an execution process of the program and the basic unit of the system running program; A system running a program is a process from creation, running to extinction.

Thread: a thread is an execution unit in a process. It is responsible for the execution of programs in the current process. There is at least one thread in a process. There can be multiple threads in a process, and this application can also be called a multithreaded program.

In short: after a program runs, there is at least one process, and a process can contain multiple threads

Thread create thread class

//1. Create a subclass of Thread class
public class MyThread extends Thread{
    //2. Override the run method in the Thread class in the subclass of the Thread class and set the Thread task (what do you want to do to start the Thread?)
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            System.out.println("run:"+i);
        }
    }
}

/*
    The first way to create a multithreaded program: create a subclass of the Thread class
    java.lang.Thread Class: a class that describes threads. If we want to implement multithreaded programs, we must inherit the Thread class

    Implementation steps:
        1.Create a subclass of the Thread class
        2.Override the run method in the Thread class in the subclass of the Thread class and set the Thread task (what do you want to do to start the Thread?)
        3.Create a subclass object of the Thread class
        4.Call the start method in the Thread class to start a new Thread and execute the run method
             void start() Start the thread to execute; The Java virtual machine calls the run method of the thread.
             The result is that two threads run concurrently; The current thread (the main thread) and another thread (the new thread created executes its run method).
             It is illegal to start a thread multiple times. Especially when the thread has finished execution, it cannot be restarted.
    java The program belongs to preemptive scheduling. The thread has high priority and the thread has priority to execute; At the same priority, select one execution at random
 */
public class DemoThread {
    public static void main(String[] args) {
        //3. Create subclass objects of Thread class
        MyThread mt = new MyThread();
        //4. Call the start method in the Thread class to start a new Thread and execute the run method
        mt.start();

        for (int i = 0; i <20 ; i++) {
            System.out.println("main:"+i);
        }
    }
}

Ruable create thread class

//1. Create an implementation class of Runnable interface
public class RunnableImpl implements Runnable{
    //2. Rewrite the run method of the Runnable interface in the implementation class to set the thread task
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
//1. Create an implementation class of Runnable interface
public class RunnableImpl2 implements Runnable{
    //2. Rewrite the run method of the Runnable interface in the implementation class to set the thread task
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            System.out.println("HelloWorld"+i);
        }
    }
}
/*
    The second way to create a multithreaded program is to implement the Runnable interface
    java.lang.Runnable
        Runnable Interfaces should be implemented by classes that intend to execute their instances through a thread. Class must define a parameterless method called run.
    java.lang.Thread Class construction method
        Thread(Runnable target) Assign a new Thread object.
        Thread(Runnable target, String name) Assign a new Thread object.

    Benefits of implementing Runnable interface to create multithreaded programs:
        1.The limitation of single inheritance is avoided
            A class can only inherit one class (a person can only have one parent). If a class inherits Thread class, it cannot inherit other classes
            The Runnable interface is implemented. You can also inherit other classes and implement other interfaces
        2.It enhances the expansibility of the program and reduces the coupling (decoupling) of the program
            The way to implement the Runnable interface separates (decouples) setting the thread task from starting a new thread
            In the implementation class, the run method is overridden: it is used to set the thread task
            Create a Thread class object and call the start method: used to start a new Thread
 */
public class DemoRunnable {
    public static void main(String[] args) {
        //3. Create an implementation class object of Runnable interface
        RunnableImpl run = new RunnableImpl();
        //4. Create a Thread class object and construct the implementation class object passing the Runnable interface in the method
        //Thread t = new Thread(run);// Print thread name
        Thread t = new Thread(new RunnableImpl2());//Print HelloWorld
        //5. Call the start method in the Thread class to start a new Thread to execute the run method
        t.start();

        for (int i = 0; i <20 ; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

Methods commonly used in threads

public String getName() :Gets the name of the current thread.
public void start() :Causes this thread to start executing; Java The virtual machine calls this thread run method.
public void run() :The tasks to be performed by this thread define the code here.
public static void sleep(long millis) :Pauses (temporarily stops execution) the currently executing thread for the specified number of milliseconds.
public static Thread currentThread() :Returns a reference to the thread object currently executing.
/*
    Get the name of the thread:
        1.Use the method getName() in the Thread class
            String getName() Returns the name of the thread.
        2.You can first get the thread currently executing, and use the method getName() in the thread to get the name of the thread
            static Thread currentThread() Returns a reference to the thread object currently executing.
 */
// Define a subclass of Thread class
public class MyThread extends Thread{
    //Override the run method in the Thread class to set the Thread task
    @Override
    public void run() {
        //Get thread name
        //String name = getName();
        //System.out.println(name);

        //Thread t = Thread.currentThread();
        //System.out.println(t);//Thread[Thread-0,5,main]
        //String name = t.getName();
        //System.out.println(name);

        //Chain programming
        System.out.println(Thread.currentThread().getName());
    }
}
public class DemoGetThreadName {
    public static void main(String[] args) {
        //Create a subclass object of the Thread class
        MyThread mt = new MyThread();
        //Call the start method to start a new thread and execute the run method
        mt.start();

        new MyThread().start();
        new MyThread().start();

        //Chain programming
        System.out.println(Thread.currentThread().getName());
    }
}

/*
    Set the name of the thread: (learn)
        1.Use the method setname (name) in the Thread class
            void setName(String name) Change the thread name to be the same as the parameter name.
        2.Create a construction method with parameters, and pass the name of the thread with parameters; Call the parameterized construction method of the parent class, pass the thread name to the parent class, and let the parent class (Thread) give a name to the child thread
            Thread(String name) Assign a new Thread object.
 */
public class MyThread extends Thread{

    public MyThread(){}

    public MyThread(String name){
        super(name);//Pass the thread name to the parent class and let the parent class (Thread) give a name to the child thread
    }

    @Override
    public void run() {
        //Gets the name of the thread
        System.out.println(Thread.currentThread().getName());
    }
}
public class DemoSetThreadName {
    public static void main(String[] args) {
        //Turn on Multithreading
        MyThread mt = new MyThread();
        mt.setName("cockroach");
        mt.start();

        //Turn on Multithreading
        new MyThread("Wangcai").start();
    }
}
/*
    public static void sleep(long millis):Pauses (temporarily stops execution) the currently executing thread for the specified number of milliseconds.
    After the end of milliseconds, the thread continues to execute
 */
public class DemoSleep {
    public static void main(String[] args) {
        //Analog stopwatch
        for (int i = 1; i <=60 ; i++) {
            System.out.println(i);

            //Use the sleep method of Thread class to make the program sleep for 1 second
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Anonymous internal creation thread

/*
    Creating threads by anonymous inner classes

    Anonymous: no name
    Inner class: a class written inside other classes

    Anonymous inner class function: simplify code
        Inherit the subclass from the parent class, override the methods of the parent class, and create subclass objects in one step
        The implementation class implements the class interface, rewrites the methods in the interface, creates the implementation class object, and synthesizes it in one step
    The end product of anonymous inner classes: subclass / implementation class objects, and this class has no name

    Format:
        new Parent class / interface (){
            Duplicate methods in parent class / interface
        };
 */
public class DemoInnerClassThread {
    public static void main(String[] args) {
        //The parent class of a Thread is Thread
        // new MyThread().start();
        new Thread(){
            //Override the run method to set the thread task
            @Override
            public void run() {
                for (int i = 0; i <20 ; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+"dark horse");
                }
            }
        }.start();

        //Thread interface Runnable
        //Runnable r = new RunnableImpl(); / / polymorphic
        Runnable r = new Runnable(){
            //Override the run method to set the thread task
            @Override
            public void run() {
                for (int i = 0; i <20 ; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+"programmer");
                }
            }
        };
        new Thread(r).start();

        //Ways to simplify interfaces
        new Thread(new Runnable(){
            //Override the run method to set the thread task
            @Override
            public void run() {
                for (int i = 0; i <20 ; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+"Intelligence Podcast");
                }
            }
        }).start();
    }
}

Thread safe - synchronous code block

/*
    There is a thread safety problem in the ticket selling case
    Sold non-existent tickets and duplicate tickets
    A solution to thread safety problem: use synchronous code blocks
    Format:
        synchronized(Lock object) {code that may cause thread safety problems (code that accesses shared data)}
    be careful:
        1.Any object can be used through the lock object in the code block
        2.However, it must be ensured that the lock object used by multiple threads is the same
        3.Lock object function:
            Lock the synchronization code block and let only one thread execute in the synchronization code block
 */
public class RunnableImpl implements Runnable{
    //Define a ticket source shared by multiple threads
    private  int ticket = 100;

    //Create a lock object
    Object obj = new Object();

    //Set thread task: selling tickets
    @Override
    public void run() {
        //Use the dead loop to repeat the ticket selling operation
        while(true){
           //Synchronous code block
            synchronized (obj){
                //First judge whether the ticket exists
                if(ticket>0){
                    //Improve the probability of safety problems and let the program sleep
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //Ticket exists, ticket selling--
                    System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                    ticket--;
                }
            }
        }
    }
}

/*
    Simulated ticket selling case
    Create three threads and start them at the same time to sell the shared tickets
 */
public class DemoTicket {
    public static void main(String[] args) {
        //Create an implementation class object for the Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create a Thread class object and construct the implementation class object passing the Runnable interface in the method
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to start multithreading
        t0.start();
        t1.start();
        t2.start();
    }
}

Thread safety synchronization method

public class RunnableImpl implements Runnable{
    //Define a ticket source shared by multiple threads
    private static int ticket = 100;

    //Set thread task: selling tickets
    @Override
    public void run() {
        System.out.println("this:"+this);//this:com.itheima.demo08.Synchronized.RunnableImpl@58ceff1
        //Use the dead loop to repeat the ticket selling operation
        while(true){
            payTicketStatic();
        }
    }

    /*
        Static synchronization method
        Who is the lock object?
        It can't be this
        this It is generated after the object is created, and the static method takes precedence over the object
        The lock object of the static method is the class attribute -- > class file object (reflection) of this class
     */
    public static /*synchronized*/ void payTicketStatic(){
        synchronized (RunnableImpl.class){
            //First judge whether the ticket exists
            if(ticket>0){
                //Improve the probability of safety problems and let the program sleep
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //Ticket exists, ticket selling--
                System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                ticket--;
            }
        }

    }

    /*
        Define a synchronization method
        Synchronous methods also lock the code inside the method
        Let only one thread execute
        Who is the lock object of the synchronization method?
        Is to implement the class object new RunnableImpl()
        It's this
     */
    public /*synchronized*/ void payTicket(){
        synchronized (this){
            //First judge whether the ticket exists
            if(ticket>0){
                //Improve the probability of safety problems and let the program sleep
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //Ticket exists, ticket selling--
                System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                ticket--;
            }
        }

    }
}

public class DemoTicket {
    public static void main(String[] args) {
        //Create an implementation class object for the Runnable interface
        RunnableImpl run = new RunnableImpl();
        System.out.println("run:"+run);//run:com.itheima.demo08.Synchronized.RunnableImpl@58ceff1
        //Create a Thread class object and construct the implementation class object passing the Runnable interface in the method
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to start multithreading
        t0.start();
        t1.start();
        t2.start();
    }
}

Lock lock

java.util.concurrent.locks.Lock mechanism provides a wider range of locking operations than synchronized code blocks and synchronized methods. Synchronized code blocks / synchronized methods have Lock functions. In addition, they are more powerful and object-oriented.

Lock lock is also known as synchronous lock. The locking and releasing methods are as follows:
public void lock(): add synchronization lock.
public void unlock(): release the synchronization lock

/*
    There is a thread safety problem in the ticket selling case
    Sold non-existent tickets and duplicate tickets

    Three solutions to thread safety: using Lock lock
    java.util.concurrent.locks.Lock Interface
    Lock The implementation provides a wider range of locking operations than can be obtained using synchronized methods and statements.
    Lock Methods in the interface:
        void lock()Get lock.
        void unlock()  Release the lock.
    java.util.concurrent.locks.ReentrantLock implements Lock Interface


    Use steps:
        1.Create a ReentrantLock object at the member location
        2.Call lock in the Lock interface before getting code for security problems.
        3.Call the method unlock release lock in the Lock interface after the code that may have security problems.
 */
public class RunnableImpl implements Runnable{
    //Define a ticket source shared by multiple threads
    private  int ticket = 100;

    //1. Create a ReentrantLock object at the member location
    Lock l = new ReentrantLock();

    //Set thread task: selling tickets
    @Override
    public void run() {
        //Use the dead loop to repeat the ticket selling operation
        while(true){
            //2. call the lock in the Lock interface before getting code for security problems.
            l.lock();

            //First judge whether the ticket exists
            if(ticket>0){
                //Improve the probability of safety problems and let the program sleep
                try {
                    Thread.sleep(10);
                    //Ticket exists, ticket selling--
                    System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //3. call the method unlock release lock in the Lock interface after the code that may have security problems.
                    l.unlock();//The lock will be released whether the program is abnormal or not
                }
            }
        }
    }
    
    public class DemoTicket {
    public static void main(String[] args) {
        //Create an implementation class object for the Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create a Thread class object and construct the implementation class object passing the Runnable interface in the method
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to start multithreading
        t0.start();
        t1.start();
        t2.start();
    }
}

Communication between threads

/*
    Wait for wake-up case: communication between threads
        Create a customer thread (consumer): inform the boss of the type and quantity of steamed stuffed buns to be, call the wait method, give up cpu execution, and enter the WAITING state (unlimited WAITING)
        Create a boss thread (producer): it takes 5 seconds to make a stuffed buns. After doing the steamed stuffed buns, call the notify method to wake customers to eat baozi.

    be careful:
        The customer and boss threads must be wrapped in synchronous code blocks to ensure that only one of the wait and wake-up can be executed
        Lock objects used synchronously must be unique
        Only lock objects can call the wait and notify methods

    Obejct Methods in classes
    void wait()
          Causes the current thread to wait before another thread calls the notify() method or notifyAll() method of this object.
    void notify()
          Wake up a single thread waiting on this object monitor.
          Will continue to execute the code after the wait method
 */
public class DemoWaitAndNotify {
    public static void main(String[] args) {
        //Create a lock object to ensure uniqueness
        Object obj = new Object();
        // Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
               //I've been waiting to buy steamed stuffed buns
               while(true){
                   //To ensure that there is only one execution of waiting and waking threads, synchronization technology needs to be used
                   synchronized (obj){
                       System.out.println("Tell the boss the type and quantity of steamed buns you want");
                       //Call the wait method, abandon cpu execution, and enter the WAITING state (infinite wait)
                       try {
                           obj.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       //Code executed after wake-up
                       System.out.println("The steamed stuffed bun is ready,Eat!");
                       System.out.println("---------------------------------------");
                   }
               }
            }
        }.start();

        //Create a boss thread (producer)
        new Thread(){
            @Override
            public void run() {
                //Keep making steamed stuffed buns
                while (true){
                    //It took five seconds to make steamed stuffed buns
                    try {
                        Thread.sleep(5000);//Take five seconds to make steamed stuffed buns
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //To ensure that there is only one execution of waiting and waking threads, synchronization technology needs to be used
                    synchronized (obj){
                        System.out.println("The boss will make steamed stuffed buns in five seconds,Inform the customer,You can eat steamed stuffed buns");
                        //After making the steamed stuffed buns, call notify method to wake customers to eat baozi.
                        obj.notify();
                    }
                }
            }
        }.start();
    }
}

/*
    There are two ways to enter timewaiting
    1.Using the sleep(long m) method, after the end of the millisecond value, the thread wakes up and enters the Runnable/Blocked state
    2.Use the wait(long m) method. If the wait method is not awakened by notify after the end of the millisecond value, it will automatically wake up, and the thread will wake up and enter the Runnable/Blocked state

    Wake up method:
         void notify() Wake up a single thread waiting on this object monitor.
         void notifyAll() Wake up all threads waiting on this object monitor.
 */
public class DemoWaitAndNotify {
    public static void main(String[] args) {
        //Create a lock object to ensure uniqueness
        Object obj = new Object();
        // Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
                //I've been waiting to buy steamed stuffed buns
                while(true){
                    //To ensure that there is only one execution of waiting and waking threads, synchronization technology needs to be used
                    synchronized (obj){
                        System.out.println("Customer 1 told the boss the type and quantity of steamed buns he wanted");
                        //Call the wait method, abandon cpu execution, and enter the WAITING state (infinite wait)
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //Code executed after wake-up
                        System.out.println("The steamed stuffed bun is ready,Customer 1 starts eating!");
                        System.out.println("---------------------------------------");
                    }
                }
            }
        }.start();

        // Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
                //I've been waiting to buy steamed stuffed buns
                while(true){
                    //To ensure that there is only one execution of waiting and waking threads, synchronization technology needs to be used
                    synchronized (obj){
                        System.out.println("Customer 2 told the boss the type and quantity of steamed buns he wanted");
                        //Call the wait method, abandon cpu execution, and enter the WAITING state (infinite wait)
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //Code executed after wake-up
                        System.out.println("The steamed stuffed bun is ready,Customer 2 open to eat!");
                        System.out.println("---------------------------------------");
                    }
                }
            }
        }.start();

        //Create a boss thread (producer)
        new Thread(){
            @Override
            public void run() {
                //Keep making steamed stuffed buns
                while (true){
                    //It took five seconds to make steamed stuffed buns
                    try {
                        Thread.sleep(5000);//Take five seconds to make steamed stuffed buns
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //To ensure that there is only one execution of waiting and waking threads, synchronization technology needs to be used
                    synchronized (obj){
                        System.out.println("The boss will make steamed stuffed buns in five seconds,Inform the customer,You can eat steamed stuffed buns");
                        //After making the steamed stuffed buns, call notify method to wake customers to eat baozi.
                        //obj.notify();// If there are multiple waiting threads, wake up one at random
                        obj.notifyAll();//Wake up all waiting threads
                    }
                }
            }
        }.start();
    }
}

Thread pool

/*
    2.Create a class, implement the Runnable interface, rewrite the run method, and set the thread task
 */
public class RunnableImpl implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"A new thread execution is created");
    }
}

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

/*
    Thread pool: provided after JDK 1.5
    java.util.concurrent.Executors:The factory class of thread pool, which is used to generate thread pool
    Executors Static methods in class:
        static ExecutorService newFixedThreadPool(int nThreads) Create a reusable thread pool with a fixed number of threads
        Parameters:
            int nThreads:Create the number of threads contained in the thread pool
        Return value:
            ExecutorService Interface, which returns the implementation class object of the ExecutorService interface. We can use the ExecutorService interface to receive (interface oriented programming)
    java.util.concurrent.ExecutorService:Thread pool interface
        It is used to obtain threads from the thread pool, call the start method and execute thread tasks
            submit(Runnable task) Submit a Runnable task for execution
        Method of closing / destroying thread pool
            void shutdown()
    Steps for using thread pool:
        1.Use the static method newFixedThreadPool provided in the factory class Executors of thread pool to produce a thread pool with a specified number of threads
        2.Create a class, implement the Runnable interface, rewrite the run method, and set the thread task
        3.Call the method submit in ExecutorService, transfer the thread task (implementation class), start the thread and execute the run method
        4.Call the method shutdown in ExecutorService to destroy the thread pool (not recommended)
 */
public class DemoThreadPool {
    public static void main(String[] args) {
        //1. Use the static method newFixedThreadPool provided in the factory class Executors of thread pool to produce a thread pool with a specified number of threads
        ExecutorService es = Executors.newFixedThreadPool(2);
        //3. Call the method submit in ExecutorService, transfer the thread task (implementation class), start the thread and execute the run method
        es.submit(new RunnableImpl());//pool-1-thread-1 creates a new thread execution
        //The thread pool will always be open. After using the thread, it will automatically return the thread to the thread pool, and the thread can continue to be used
        es.submit(new RunnableImpl());//pool-1-thread-1 creates a new thread execution
        es.submit(new RunnableImpl());//pool-1-thread-2 creates a new thread execution

        //4. Call the method shutdown in ExecutorService to destroy the thread pool (not recommended)
        es.shutdown();

        es.submit(new RunnableImpl());//Throw an exception, the thread pool is gone, and the thread cannot be obtained
    }

}

Lambda expression

Lambda's syntax is very concise and completely free from the constraints of object-oriented complexity. However, there are several problems that need special attention when using:

1. Lambda must have an interface, and there must be only one abstract method in the interface. Whether it is the built-in Runnable, Comparator interface or user-defined interface of JDK, lambda can be enabled only when the abstract methods in the interface exist and are unique.
2. The use of Lambda must have context inference. That is, the parameter or local variable type of the method must be the interface type corresponding to Lambda, and Lambda can be used as an instance of the interface.

Use of Lambda

/*
    Lambda Standard format for expressions:
        It consists of three parts:
            a.Some parameters
            b.An arrow
            c.A piece of code
        Format:
            (Parameter list) - > {code of some rewriting methods};
        Format of explanation:
            ():The parameter list of the abstract method in the interface is empty if there are no parameters; If there are parameters, write out the parameters. Multiple parameters are separated by commas
            ->:Pass the parameter to the method body {}
            {}:Override the method body of the abstract method of the interface
 */
public class DemoLambda {
    public static void main(String[] args) {
        //Use anonymous inner classes to realize multithreading
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" New thread created");
            }
        }).start();

        //Use Lambda expression to realize multithreading
        new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" New thread created");
            }
        ).start();

        //Optimize Lambda
        new Thread(()->System.out.println(Thread.currentThread().getName()+" New thread created")).start();
    }
}
/*
    Create the implementation class of the Runnable interface, rewrite the run method, and set the thread task
 */
public class RunnableImpl implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+" New thread created");
    }
}

Lambda, no parameter, no return value

/*
    Set a Cook interface with the only abstract method makeFood
 */
public interface Cook {
    //Defines a method makeFood that has no parameters and no return value
    public abstract void makeFood();
}

public class DemoCook {
    public static void main(String[] args) {
        //Call the invokeCook method. The parameter is the Cook interface. Pass the anonymous inner class object of the Cook interface
        invokeCook(new Cook() {
            @Override
            public void makeFood() {
                System.out.println("ate");
            }
        });

        //Use Lambda expressions to simplify the writing of anonymous inner classes
        invokeCook(()->{
            System.out.println("ate");
        });

        //Optimize Lambda
        invokeCook(()-> System.out.println("ate"));
    }

    //Define a method, pass the parameters to the Cook interface, and call the method makeFood in the Cook interface inside the method
    public static void invokeCook(Cook cook){
        cook.makeFood();
    }
}

Lambda has parameters and return values

import java.util.Arrays;

/*
    Lambda Expressions with parameters and return values
    Requirements:
        Use an array to store multiple Person objects
        The Person objects in the array are sorted in ascending order by age using the sort method of Arrays
 */
public class DemoArrays {
    public static void main(String[] args) {
        //Use an array to store multiple Person objects
        Person[] arr = {
                new Person("Zhang San",38),
                new Person("Li Si",18),
                new Person("WangTwo ",19)
        };

        //Use the sort method of Arrays to sort the Person objects in the array in ascending order (front to back) by age
        /*Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        });*/

        //Use Lambda expressions to simplify anonymous inner classes
        Arrays.sort(arr,(Person o1, Person o2)->{
            return o1.getAge()-o2.getAge();
        });

        //Optimize Lambda
        Arrays.sort(arr,(o1, o2)->o1.getAge()-o2.getAge());

        //Traversal array
        for (Person p : arr) {
            System.out.println(p);
        }
    }
}

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Keywords: Java Back-end

Added by inosent1 on Wed, 08 Dec 2021 19:55:32 +0200