Fundamentals of Java language Day23

Posted by johnwayne77 on Thu, 13 Jan 2022 02:06:31 +0100

1, Wait for wake-up mechanism

1. Inter thread communication


2. Overview of waiting wake-up mechanism

What is the waiting wake-up mechanism?
This is a collaboration mechanism between multiple threads. When it comes to threads, we often think of the race between threads, such as competing for locks, but this is not the whole story. There will also be a cooperation mechanism between threads. Just like you and your colleagues in the company, you may have competition for promotion, but more often you work together to complete some tasks.

After a thread performs a specified operation, it enters the wait state (wait()) and waits for other threads to wake up after executing their specified code (notify()); When there are multiple threads waiting, you can use notifyAll() to wake up all waiting threads if necessary.

wait/notify is a cooperative mechanism between threads.

Methods in waiting for wake-up:
The wake-up waiting mechanism is used to solve the problem of inter thread communication. The meanings of the three methods used are as follows:

  • Wait: the thread is no longer active, no longer participates in scheduling, and enters the wait set. Therefore, CPU resources will not be wasted, nor will it compete for locks. At this time, the thread state is WAITING. It also waits for other threads to perform a special action, that is, "notify" the threads WAITING on this object to be released from the wait set and re-enter the ready queue;
  • notify: select a thread in the wait set of the notified object to release; For example, when a restaurant has a free seat, the customer waiting for the longest meal takes the first seat;
  • notifyAll: release all threads on the wait set of the notified object.

be careful:
Even if only one waiting thread is notified, the notified thread cannot resume execution immediately, because the place where it was interrupted was in the synchronization block, and now it does not hold the lock, so she needs to try to obtain the lock again (probably facing competition from other threads). Only after success can it be called at the beginning
Resume execution after the wait method.
The summary is as follows:

  • If the lock can be obtained, the thread will change from WAITING state to RUNNABLE state;
  • Otherwise, when it comes out of the wait set and enters the entry set, the thread will change from the WAITING state to the BLOCKED state

Details of calling wait and notify methods:

  1. The wait method and notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after using the wait method called by the same lock object through notify;
  2. The wait method and notify method are methods belonging to the Object class. Because: the lock Object can be any Object, and the class of any Object inherits the Object class;
  3. The wait method and notify method must be used in the synchronization code block or synchronization function. Because: these two methods must be called through the lock object.

3. Demand analysis of waiting wake-up mechanism (producer and consumer issues)

4. Wait for the wake-up mechanism code to implement the package subclass & package shop class

package com.itheima.demo01.WaitAndNotify;
/*
    Resource class: package subclass
	Set the properties of the package
		skin
		Sink
		Status of steamed stuffed bun: true but not false
 */
public class BaoZi {
    //skin
    String pi;
    //Sink
    String xian;
    //Status of steamed stuffed bun: true but not false. Set the initial value to false and there is no steamed stuffed bun
    boolean flag = false;

}

package com.itheima.demo01.WaitAndNotify;
/*
    Producer (steamed stuffed bun shop) class: it is a Thread class that can inherit Thread
	Set up thread task (run): produce package
	Judge the state of steamed stuffed bun
	true:There are steamed stuffed buns
		The package store calls the wait method to enter the waiting state
	false:No steamed stuffed bun
		Steamed buns shop produces steamed buns
		Add some fun: produce two kinds of steamed stuffed buns alternately
			There are two states (i%2==0)
		The steamed stuffed bun shop has produced steamed stuffed buns
		Modify the status of the steamed stuffed bun to true
		Wake up the eating thread and let the eating thread eat steamed stuffed buns

	be careful:
	    Relationship between package sub thread and package sub thread -- > communication (mutually exclusive)
	    Synchronization technology must be used at the same time to ensure that only one of the two threads is executing
	    The lock object must be unique. You can use the package sub object as the lock object
	    The steamed stuffed bun shop class and the food class need to pass in the steamed stuffed bun object as a parameter
	        1.You need to create a package sub variable at the member location
	        2.Use the construction method with parameters to assign a value to this package sub variable
 */
public class BaoZiPu extends Thread{
    //1. You need to create a package sub variable at the member location
    private BaoZi bz;

    //2. Use the construction method with parameters to assign a value to this package sub variable
    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }

    //Set up thread task (run): produce package
    @Override
    public void run() {
        //Define a variable
        int count = 0;
        //Let the steamed stuffed bun shop produce steamed stuffed buns all the time
        while(true){
            //Synchronization technology must be used at the same time to ensure that only one of the two threads is executing
            synchronized (bz){
                //Judge the state of steamed stuffed bun
                if(bz.flag==true){
                    //The package store calls the wait method to enter the waiting state
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //After being awakened, the steamed stuffed bun shop produces steamed stuffed buns
                //Add some fun: produce two kinds of steamed stuffed buns alternately
                if(count%2==0){
                    //Production of thin skinned steamed stuffed buns with three delicacies
                    bz.pi = "Thin skin";
                    bz.xian = "Three fresh fillings";
                }else{
                    //Production of frozen beef and scallion
                    bz.pi = "Ice skin";
                    bz.xian = "Beef and scallion";

                }
                count++;
                System.out.println("The steamed stuffed bun shop is in production:"+bz.pi+bz.xian+"steamed stuffed bun");
                //It takes three seconds to produce steamed stuffed buns
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //The steamed stuffed bun shop has produced steamed stuffed buns
                //Modify the status of the steamed stuffed bun to true
                bz.flag = true;
                //Wake up the eating thread and let the eating thread eat steamed stuffed buns
                bz.notify();
                System.out.println("The steamed stuffed bun shop has been produced:"+bz.pi+bz.xian+"steamed stuffed bun,You can start eating");
            }
        }
    }
}

5. Wait for the wake-up mechanism code to implement the food class & test class

package com.itheima.demo01.WaitAndNotify;
/*
    Consumer (food) class: a Thread class that can inherit Thread
	Set thread task (run): eat steamed stuffed bun
	Judge the state of steamed stuffed bun
	false:No steamed stuffed bun
		Call the wait method to enter the waiting state after eating
	true:There are steamed stuffed buns
		Eat steamed stuffed bun
		Eat steamed stuffed bun
		Modify the status of the package to false
		Eat goods to wake up the thread of steamed stuffed bun shop and produce steamed stuffed buns
 */
public class ChiHuo extends Thread{
    //1. You need to create a package sub variable at the member location
    private BaoZi bz;

    //2. Use the construction method with parameters to assign a value to this package sub variable
    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }
    //Set thread task (run): eat steamed stuffed bun
    @Override
    public void run() {
        //Use the dead cycle to make the food eat steamed stuffed buns all the time
        while (true){
            //Synchronization technology must be used at the same time to ensure that only one of the two threads is executing
            synchronized (bz){
                //Judge the state of steamed stuffed bun
                if(bz.flag==false){
                    //Call the wait method to enter the waiting state after eating
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //Code executed after being awakened, eat steamed stuffed buns
                System.out.println("The food is eating:"+bz.pi+bz.xian+"Steamed stuffed bun");
                //Eat steamed stuffed bun
                //Modify the status of the package to false
                bz.flag = false;
                //Eat goods to wake up the thread of steamed stuffed bun shop and produce steamed stuffed buns
                bz.notify();
                System.out.println("The food has been taken away:"+bz.pi+bz.xian+"My steamed stuffed bun is finished,The steamed stuffed bun shop began to produce steamed stuffed buns");
                System.out.println("----------------------------------------------------");
            }
        }
    }
}

package com.itheima.demo01.WaitAndNotify;
/*
    Test class:
	Contains the main method, the entry of program execution, and starts the program
	Create a package sub object;
	Create buns shop thread, start and produce buns;
	Create a food thread, open it and eat steamed stuffed buns;
 */
public class Demo {
    public static void main(String[] args) {
        //Create a package sub object;
        BaoZi bz =new BaoZi();
        //Create buns shop thread, start and produce buns;
        new BaoZiPu(bz).start();
        //Create a food thread, open it and eat steamed stuffed buns;
        new ChiHuo(bz).start();
    }
}

2, Thread pool

1. Concept and principle of thread pool

  • Thread pool: in fact, it is a container containing multiple threads, in which threads can be used repeatedly, eliminating the operation of frequently creating thread objects and consuming too many resources without repeatedly creating threads.


2. Code implementation of thread pool

package com.itheima.demo02.ThreadPool;
/*
    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");
    }
}

package com.itheima.demo02.ThreadPool;

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

/*
    Thread pool: jdk1 Provided after 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 Demo01ThreadPool {
    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
    }

}

3, Lambda expression

1. Overview of functional programming ideas

In mathematics, a function is a set of calculation schemes with input and output, that is, "what to do with". Relatively speaking, object-oriented overemphasizes that "things must be done in the form of objects", while functional thinking tries to ignore the complex object-oriented syntax - emphasizing what to do rather than what form to do.

  • Object - oriented thinking: do a thing, find an object that can solve it, call the method of the object, and finish it
  • Functional programming thought: as long as the results can be obtained, it doesn't matter who does it or how to do it. It pays attention to the results rather than the process

2. Redundant Runnable code

package com.itheima.demo03.Lambda;
/*
    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");
    }
}

package com.itheima.demo03.Lambda;
/*
    The multithreaded program is implemented by implementing the Runnable interface
 */
public class Demo01Runnable {
    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 that passes the Runnable interface in the method
        Thread t = new Thread(run);
        //Call the start method to start a new thread and execute the run method
        t.start();

        //Simplify the code, use anonymous internal classes, and implement multithreaded programs
        Runnable r = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" New thread created");
            }
        };
        new Thread(r).start();

        //Simplified code
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" New thread created");
            }
        }).start();
    }
}

3. Transformation of programming ideas & experience the better writing method of Lambda

package com.itheima.demo03.Lambda;

public class Demo02Lambda {
    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();

4.Lambda standard format

Lambda Standard format for expressions:
    It consists of three parts:
        a.Some parameters
        b.An arrow
        c.A piece of code
    format:
        (parameter list) -> {Some code for rewriting methods};
    Explanation format:
        ():Parameter list of abstract method in interface,No parameters,It's empty;Write out parameters if there are parameters,Multiple parameters are separated by commas
        ->:Meaning of transmission,Pass parameters to the method body{}
        {}:Override the method body of the abstract method of the interface

5. Practice of no parameter and no return value of lambda expression

package com.itheima.demo04.Lambda;
/*
    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();
}

package com.itheima.demo04.Lambda;
/*
    Requirements:
        Given a Cook interface, it contains the only abstract method makeFood, with no parameters and no return value.
        Use Lambda's standard format to call the invokeCook method and print out "eat!" word
 */
public class Demo01Cook {
    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();
    }
}

6. Practice of lambda expression with parameters and return values

package com.itheima.demo05.Lambda;

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

package com.itheima.demo05.Lambda;

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 Demo01Arrays {
    public static void main(String[] args) {
        //Use an array to store multiple Person objects
        Person[] arr = {
                new Person("Liuyan",38),
                new Person("Delireba",18),
                new Person("Gulinaza",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);
        }
    }
}

7. Practice of lambda expression with parameters and return values (user-defined interface)

package com.itheima.demo06.Lambda;
/*
    Given a Calculator calculator interface with an abstract method calc, you can add two int numbers to get the sum value
 */
public interface Calculator {
    //Define a method to calculate the sum of two int integers and return the result
    public abstract int calc(int a,int b);
}

package com.itheima.demo06.Lambda;

/*
    Lambda Expressions with parameters and return values
    Requirements:
        Given a Calculator calculator interface with an abstract method calc, you can add two int numbers to get the sum value
        The invokeCalc method is called using Lambda's standard format to complete the addition calculation of 120 and 130
 */
public class Demo01Calculator {
    public static void main(String[] args) {
        //Call the invokeCalc method. The parameter of the method is an interface. Anonymous inner classes can be used
        invokeCalc(10, 20, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });

        //Simplify writing anonymous inner classes using Lambda expressions
        invokeCalc(120,130,(int a,int b)->{
            return a + b;
        });

        //Optimize Lambda
        invokeCalc(120,130,(a,b)-> a + b);
    }

    /*
        Define a method
        Parameter passes two integers of type int
        Parameter passing Calculator interface
        Method calls the method calc in the Calculator to calculate the sum of two integers
     */
    public static void invokeCalc(int a,int b,Calculator c){
        int sum = c.calc(a,b);
        System.out.println(sum);
    }
}

8.Lambda omitted format & premise of lambda use

package com.itheima.demo07.Lambda;

import java.util.ArrayList;

/*
    Lambda Expression: it is derivable and can be omitted
    Any content derived from the context can be omitted
    Contents that can be omitted:
        1.(Parameter list): the data type of the parameter list in parentheses, which can be omitted
        2.(Parameter list): if there is only one parameter in parentheses, the type and () can be omitted
        3.{Some codes}: if there is only one line of code in {}, you can omit ({}, return, semicolon) whether there is a return value or not
            Note: to omit {}, return, semicolons must be omitted together
 */
public class Demo01ArrayList {
    public static void main(String[] args) {
        //JDK1. Before version 7, you must write the generic types before and after creating a collection object
        ArrayList<String> list01 = new ArrayList<String>();

        //JDK1. After version 7, the generics after the = sign can be omitted, and the generics after the = sign can be derived from the generics before
        ArrayList<String> list02 = new ArrayList<>();
    }
}

9. Premise of lambda

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 used only when the abstract methods in the interface exist and are unique.
  2. Using 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.

Note: an interface with only one abstract method is called "functional interface"

Topics: Java