java foundation summary

Keywords: Java Interview

1, Introduction to java

java features

1. Object oriented

Basic features: class, object

Three characteristics:

  • Encapsulation: internal details are transparent to external calls, and external calls do not need to be modified or care about internal implementation

  • Inheritance: inherit the methods of the base class and make your own changes and / or extensions

  • Polymorphism: the parent class reference points to the child class object, and the parent class object can be dropped

2. Robustness

3. Cross platform

JDK JRE JVM

JDK:

Java development kit

JRE:

Java runtime environment

JVM:

Java virtual machine

There are three ways to load classes

1. Create an instance of a class with the new keyword (static loading) and load it with the new method at runtime. 2. Call the Class.forName() method (dynamic loading) to load the type through reflection and create an object instance

3. Call the loadClass() method (dynamic loading) of a ClassLoader instance and load it through the loadClass() method of the ClassLoader instance. Applications can implement their own class loader by inheriting ClassLoader.

Loading: a stage of Class loading process: find such bytecode file through the full qualification of a Class, and create a Class object using the bytecode file

Verification: the purpose is to ensure that the information contained in the byte stream of the Class file meets the requirements of the current virtual machine and will not endanger the security of the virtual machine. It mainly includes four kinds of verification, file format verification, metadata verification, bytecode verification and symbol reference verification.

Preparation: allocate memory for class variables (i.e. static modified field variables) and set the initial value of such variables, i.e. 0 (e.g. static int i=5; here only I is initialized to 0, and the value of 5 will be assigned during initialization). Static modified with final is not included here, because final will be allocated during compilation. Note that initialization will not be allocated for instance variables, Class variables are allocated in the method area, while instance variables are allocated to the Java heap along with the object.

Parsing: it is mainly the process of replacing the symbol reference in the constant pool with a direct reference. Symbol reference is a set of symbols to describe the target, which can be any literal, while direct reference is a pointer directly to the target, a relative offset, or a handle indirectly located to the target. There are class or interface parsing, field parsing, class method parsing and interface method parsing (this involves the reference of bytecode variables. For more details, please refer to in depth Java virtual machine).

Initialization: in the last stage of class loading, if the class has a superclass, it will be initialized, and the static initializer and static initialization member variables will be executed (for example, the static variable that has only initialized the default value will be assigned in this stage, and the member variables will also be initialized)

These are the five processes of class loading. The task of class loader is to read the binary byte stream of a class according to the fully qualified name of a class, and then convert it into a java.lang.Class object instance corresponding to the target class. Three kinds of loaders are provided in the virtual machine, including Bootstrap class loader, Extension class loader and System Class loader (also known as application class loader)

Bootstrap class loader the bootstrap class loader mainly loads the classes required by the JVM itself. This class loading is implemented in C + + language and is a part of the virtual machine itself. It is responsible for_ Load the core class library under the home > / lib path or the jar package under the path specified by the - Xbootclasspath parameter into memory. Note that the virtual machine loads the jar package according to the file name, such as rt.jar. If the file name is not recognized by the virtual machine, it will not work even if the jar package is thrown into the Lib directory (for security reasons, bootstrap boot class loader only loads classes with package names beginning with Java, javax, sun, etc.). Extension class loader extension class loader refers to sun company (acquired by Oracle) The sun.misc.Launcher$ExtClassLoader class implemented by the Java language is the static internal class of the Launcher. It is responsible for loading the class library in the < java_home > / lib / ext directory or by the System variable - Djava.ext.dir. Developers can directly use the standard extension class loader Classloader, also known as application loader, refers to sun.misc.Launcher$AppClassLoader implemented by Sun company. It is responsible for loading the class library under the path specified by the System classpath java -classpath or - D java.class.path, that is, the classpath we often use. Developers can directly use the System classloader. Generally, this class loading is the default class loading in the program The class loader can be obtained through the ClassLoader#getSystemClassLoader() method.

Working process of parent delegation mechanism:

If a class loader receives a request from the class loader, it will not try to load the class itself. Instead, it delegates the request to the parent loader to complete it. This is true for class loaders at each level

Therefore, all load requests will eventually be sent to the Bootstrap class loader (boot class loader). The child loader will try to load itself only when the parent class load feedback that it cannot load the request (the required class is not found in its search scope).

Advantages of parental delegation model:

Java classes have a hierarchical relationship with their loaders. For example, the class java.lang.Object is stored in rt.jart. No matter which class loader loads this class, it is loaded by the Bootstrap class loader at the top of the parental delegation model. Therefore, the Object class is the same class in various classloader environments of the program. On the contrary, if there is no If the user writes a class called "Java. Lang. Object" and stores it in the ClassPath of the program, multiple different Object classes will appear in the system. The most basic behavior in the Java type system cannot be guaranteed. The application will also be in chaos

2, Java basic syntax

1. Variable: used to save data in memory

2. Data type

3. Cast type

4. Reference type: String connection "+"

Interview question: why is String designed to be immutable?

(1) Need for String constant pool: when creating a String object, if the String value already exists in the constant pool, a new object will not be created, but the existing object will be referenced.

(2) It ensures the uniqueness of hash code and allows String objects to cache HashCode

(3) Avoid security problems: in network connection and database connection, strings are often used as parameters, such as network connection address, URL, file path, and String parameters required by reflection mechanism. Its non variability can ensure the security of the connection. If the String is variable, hackers may change the value of the String pointing to the object, which will cause serious security problems.

5. Operator

Arithmetic operator: + - */

Logical operators: & |! & |^

Bitwise operator: < < shift left by 2 > > shift right by 2

Ternary operator: (conditional expression)? Expression 1: expression 2

6. Process control

(1)if-else

(2) How to get scanner from keyboard

(3)switch-case

  • The variable type in the switch statement can be byte, short, int or char. Starting from Java SE 7, switch supports String type, and the case label must be a String constant or literal.

switch(expression){
    case value :
       //sentence
       break; //Optional
    case value :
       //sentence
       break; //Optional
    //You can have any number of case statements
    default : //Optional
       //sentence
}

(4) for loop

public class Test2 {
    public static void main(String[] args) {
        for (int i = 100; i < 1000;i++) {
            int ge = i % 10;
            int shi = i % 100 /10;
            int bai = i / 100;
            if (i == ge*ge*ge + shi*shi*shi + bai*bai*bai) {
                System.out.println("Number of daffodils:" + i);
            }
        }
    }
}

(5) while loop

(6)do-while

While is to judge first, while do while is to judge first and execute at least once

(7) Use of special Keywords: break (end the current cycle), continue (end the current cycle)

7. Array

1. One dimensional array

2. Get array length traversal

public class ArrayTest1 {
    public static void main(String[] args) {
        int[] num = {1,4,3,2,8,6};
        System.out.println(num.length);//Get length
        //Traverse each element of the array
        for (int s: num){
            System.out.print(s + " ");
        }
    }
}
​
     Sorting: Array.sort();
​
     Search: Array.binarySearch();
​
      Print: Array.toString();
​
      Copy: Array.copyof();

3. Multidimensional array

4. Random number

Formula: Math.random()*(n-m + 1)+m to generate random numbers greater than or equal to m and less than N;

Math.random();// Generate a random number between [0, 1)

5. Array copy and array flip

String[] arr = {"James","Thick eyebrow","Kobe","Wei Shao","Harden"};
        //Copy array
        String[] arr1 = new String[arr.length];
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] = arr[i];
        }
        //Array inversion mode 1
        for (int i = 0; i < arr.length / 2; i++) {
            String temp = arr[i];
            arr[i] = arr[arr.length - i -1];
            arr[arr.length - i -1] = temp;
        }
        //Reverse mode 2
        for (int i = 0, j  = arr.length -1; i < j; i++,j--) {
            String temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        //ergodic
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }

6. Find

(1) Linear search

    public static void main(String[] args) {
        String[] arr = {"James","Thick eyebrow","Kobe","Wei Shao","Harden"};
        //lookup
        Scanner scanner = new Scanner(System.in);
        System.out.println("Please enter and exit:");
        String dest = scanner.next();
        boolean isFlag = true;
        for (int i = 0; i < arr.length; i++) {
            if (dest.equals(arr[i])) {
                System.out.println("The location of the specified element found is:" + i);
                isFlag =  false;
                break;
            }
        }
        if (isFlag) {
            System.out.println("Sorry, not found!");
        }
    }
}

(2) Binary search

public class ArrayTest3 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //Binary search
        //The premise of using dichotomy search is that it must be orderly
        int[] arr2 = {-1,2,4,5,6,7,8,9,11,12};
        System.out.println("Please enter the value you are looking for:");
        int index = scanner.nextInt();
        int head = 0;
        int end = arr2.length - 1;
        boolean isFlag1 = true;
        while (head <= end) {
            int mid = (head + end) / 2;
            if (index == arr2[mid]) {
                System.out.println("Congratulations on finding it at:" + mid);
                isFlag1 = false;
                break;
            } else if (arr2[mid] > index) {
                end = mid - 1;
            } else {
                head = mid +1;
            }
        }
        if (isFlag1) {
            System.out.println("Sorry, I didn't find it");
        }
    }
}

7. Array exception

(1) Exception for array subscript out of bounds: ArrayIndexOutOfBoundsException

(2) Null pointer exception: NullPointerException

8. Time related classes

1. Date class. getTime(); calculates milliseconds
 2. The SimpleDateFormat class formats the time. format(); it returns a String
 3. Calendar interface
 The conversion between calendar fields provides some methods
      .get(Calendar.YEAR);
. get(Calendar.MONTH); / / the default is the current month minus one, starting from 0
      .get(Calendar.DAY_OF_MONTH);
      .get(Calendar.DAY_OF_WEEK);
      Calendar calendar = Calendar.getInstance();
      Date date = calendar.getTime();
4. Runtime. freeMemory(); current system space remaining
 5. System.exit(0); exit the program. If the parameter is 0, it means normal exit
 System.gc(); calling the garbage collector may not work, but it just helps

3, Objects and classes

  • Class is the description of a class of things, which is an abstract and conceptual definition

  • An object is every individual that actually exists

1. Object memory parsing

Local method stack: store C++

Program counter: the location where the current program is stored

Stack: the local variable of the current function runtime, which stores the reference address of the object and points to the heap

Method area: it is a permanent generation before JDK1.7, which is used to store class information, constants, static variables, real-time compiled code and other data loaded by the virtual machine.

Heap: used to store objects

Local method stack, program counter and stack are thread private (each thread will open up such a memory separately)

Heap and method areas are shared

2. GC of JVM

3. Objects of attributes and local variables

  • Attributes are directly defined in a pair of {} of the class, while local variables are declared in methods, method parameters, code blocks, and variables inside constructors.

  • Attributes can indicate permission problems when declared, and local variables cannot use permission modifiers.

  • Properties are loaded into heap space, while local variables are loaded into stack space.

4. Method overload

Overloading and overriding

Overload: occurs in the same class, the method name must be the same, and the parameter types must be different

Override: occurs in parent and child classes. The method name and parameter list must be the same. The return value range is less than or equal to the parent class, and the exception range thrown is less than or equal to the parent class

Equal to the parent class, and the access modifier range is greater than or equal to the parent class; if the access modifier of the parent class method is private, the child class cannot override this party

method

5. Constructor

Constructor role: creating objects

6.java Bean

  • JavaBean is a reusable component written in the Java language

  • The so-called JavaBean is a Java class that meets the following standards

    • Class is public

    • There is a public constructor without parameters

    • There are properties and corresponding get and set methods

4, Inherit

1. Succession:

Inherit the methods of the base class and make your own changes and / or extensions

  • If the constructor of the subclass does not explicitly call the constructor of the superclass, the default (no parameter) constructor of the superclass will be automatically. If the parent class only has a bad constructor, there will be no default parameterless constructor.

  • If the parent class does not have a parameterless constructor and the constructor of the child class does not explicitly call other constructors of the parent class, an error will be reported at Java compile time.

The main function of the inal modifier is to ensure that the modified object does not change the semantics in the subclass.

2. Rewrite

  • definition:

    • In a subclass, you can modify the methods inherited from the parent class as needed, which is called method reset and override

  • requirement:

    • The method overridden by the subclass must have the same method name and parameter list as the overridden method of the parent class

    • The return value type of a subclass overriding method cannot be greater than the return value of the method overridden by the parent class

    • The access permission used by the method of the subclass overriding the parent class cannot be less than that of the method overridden by the parent class (the subclass cannot override the method declared as private permission by the parent class)

    • The exception thrown by a subclass method cannot be greater than the exception of the overridden method of the parent class

  • be careful:

    • Methods with parameters of the same name in subclasses and superclasses must be declared as non static and static at the same time

3.equals

For = =:

For variables of basic data type, directly compare whether the stored "values" are equal;

If a variable of type is referenced, the address of the object pointed to is compared

For equals:

Note: the equals method cannot act on variables of basic data type

If the equals method is not overridden, the address of the object pointed to by the variable of the reference type is compared;

If the equals method is rewritten by classes such as String and Date, the content of the object pointed to is compared.

4. Polymorphism

Summary: object polymorphism: refers to the reference of the parent class pointing to the object of the child class. (or the reference of the object of the child class assigned to the parent class)

Note: at compile time, we can only call the methods declared in the parent class, but at run time, we actually execute the methods of subclasses that override the parent class

Summary: see the left for compilation and the right for operation.

5. Use of object class

1.==

  • If you are comparing variables of basic data type, compare whether the data saved by the two variables are equal

  • If the number of references type variable is compared, the comparison is whether the address value of the object is the same

2.equals

Why do I need to override the equals() method? Because if the equals method is called directly, the equals of the Object class is used to compare whether the addresses are equal. We need to compare whether the contents of the two references are equal, and we need to override the equals method.

3.toString

  • When I want to output an object reference, I actually call the toString of the current object

  • When toString is used, entity content information is returned

6. Keyword Static

  • static can be used to decorate: properties, methods, code blocks, internal classes

  • Static modification attribute: static variable (instance variable without static modification)

    • Static variables are loaded as the class loads. It can be called as a "class" static variable

    • Static variables are loaded before objects are created

    • Since the class will only be loaded once, only one copy of the static variable will be saved in the memory and stored in the static field of the method area

  • Static modification method: static method

    • Loads as the class loads. You can call static methods through the "class" point.

    • Static methods: only static methods or properties can be called; Non static methods can call either non static methods or properties, or static methods or properties.

    • Static usage details: this keyword and super key cannot be used in static methods

  • How to determine whether a property and method should be declared as static keyword in development?

    • Properties can be shared by multiple objects and will not vary with different objects

    • The method of operating static attributes is usually set to static; The methods in the tool class use static, such as Math, Arrays, Collection, etc

6. Code block

1) Function of code block: used to initialize classes and objects

(2) If the code block is decorated, only static can be used

(3) Classification: static code block, non static code block

  • Static code block:

    • There can be output statements inside

    • It is executed as the class is loaded, and it is loaded only once

    • Function: initialize class information

    • If a class always defines multiple static code blocks, it is executed in order

  • Non static code block:

    • There can be output statements inside

    • Executes as the object is created

    • Each time an object is created, a non static block of code is executed

    • Function: you can initialize the properties of the object when creating the object

7. Keyword final

  • final can modify structures: classes, methods, and variables

  • When final modifies a class, this class cannot be inherited by other classes

  • When final modifies a variable, the "variable" at this time is called a constant, and the variable declared as final cannot be changed

  • final modification attribute: the positions where assignment can be considered are (display initialization, initialization in code block, initialization in constructor)

  • Modify local variable: when modifying a formal parameter, it indicates that the type parameter is a constant. When modifying a method, assign a yes parameter to a constant parameter

  • static final is used to modify attributes: it is called a global constant (static loads with class loading, and final constant)

8. Abstract classes and abstract methods

  • abstract structures that can be modified: classes and methods (cannot be modified: properties, constructors, private methods, static methods, final classes and methods)

  • Abstract class modification: abstract class

    • Public class persontest {public static void main (string [] args) {Person1 P1 = new Person1(); / / once the Person1 class is abstracted, it cannot be instantiated}} abstract class Person1 {}

  • When modifying a method: it is called an abstract method (an abstract method has only a method declaration and no method body)

    • public abstract void eat();

    • Note 1: a class containing abstract methods must be an abstract class. Conversely, there can be no abstract methods in an abstract class

    • Note 2: a subclass can be instantiated only if it overrides all abstract methods in the parent class; If the subclass does not override all the abstract methods in the parent class, the subclass is also an abstract class and needs to be modified with abstract

9. Interface

  1. Java does not support multiple inheritance. All classes provide interfaces, so you can get the effect of multiple inheritance.

  2. The specific use of the interface reflects polymorphism

  3. Interface can actually be regarded as a specification

10. Internal class

//Returns an object of a class that implements the Comparable interface of the class
    public Comparable getComparable(){
        // Create a class that implements the Comparable interface of the class: a local inner class
       // Mode 1
        class MyComparable implements Comparable {
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        }
      return new MyComparable();
    }
public Comparable getComparable(){
        return new Comparable() {
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        };
    }

5, Exception handling

The abnormal events that occur during the execution of Java programs can be divided into two categories

  • Error: a serious problem that cannot be solved by the Java virtual machine. Such as JVM system internal error, resource exhaustion and other serious conditions (stackovlowerror and OOM)

  • Exception: other general problems caused by programming errors or accidental external elements.

throw indicates that an exception object is thrown in the method,

In the definition of throws method, throws is used to indicate that this method may throw some kind of exception, which needs to be handled by the caller of the method.

6, Assemble

  • Collection: represents a group of objects, and each object is its child element.

  • List: there is an ordered collection and can contain duplicate elements (order).

  • Set: a Collection (unique) that does not guarantee order and does not contain duplicate elements.

  • Map: you can map a key to an object with a value. The key cannot be repeated (key value pair).

1. What is the difference between String builder and StringBuffer? Why is String immutable? Why is it designed like this?

String is final modified and immutable. Each operation will produce a new string object

StringBuffer is thread safe, while StringBuilder is non thread safe. Both inherit from the AbstractStringBuilder class and can use append

1. Need for string constant pool

2. Allow String objects to cache hashcodes

3. Security String is used by many Java classes (Libraries) as parameter URL and file path

4. Because the string is immutable, it is multithread safe

2. Talk about the data structure and characteristics of common collections in Java

List

  • ArrayList: Object array (fast query, slow addition and deletion, unsafe thread and high efficiency)

  • Vector: Object array (fast query, slow addition and deletion, thread safety and low efficiency)

  • LinkedList: a two-way linked list. Before JDK1.6, it was a circular linked list. JDK1.7 cancels the cycle (slow query, fast addition and deletion, unsafe thread and high efficiency)

Map

  • HashMap: before JDK1.8, HashMap was composed of array + linked list. Array is the main body of HashMap storage elements, and linked list mainly exists to solve hash conflicts, that is, the "zipper method" to solve conflicts. After JDK1.8, great changes have been made in resolving hash conflicts. When the length of the linked list is greater than the threshold (8 by default), the linked list is transformed into a red black tree to reduce the search time (the hash table hashes the keys, and the Map structure stores key value pairs in the mapping table)

  • LinkedHashMap: LinkedHashMap inherits from HashMap, so its bottom layer is still based on zipper hash structure, that is, it is composed of array, linked list or red black tree. In addition, LinkedHashMap adds a two-way linked list on the basis of the above structure, so that the insertion order and access order of key value pairs can be realized.

  • Hashtable: it is composed of array + linked list. Array is the main body of HashMap, and linked list mainly exists to solve hash conflicts

  • TreeMap: red black tree (balanced binary sort tree)

Set

  • HashSet: it is implemented based on HashMap. The bottom layer uses HashMap to save elements (it is not guaranteed to be orderly and unique)

  • LinkedHashSet: LinkedHashSet inherits from HashSet and is internally implemented through LinkedHashMap. It is a bit similar to the LinkedHashMap we mentioned earlier. Its internal implementation is based on Hashmap, but there is still a little difference.

  • TreeSet: red black tree, self balanced sorting binary tree (NATURAL sorting can be realized, such as a-z)

3. Differences between Collections and Collections

  • Collection is the superior interface of a collection, which is inherited by the Set and List interfaces

  • Collections is a collection tool class, which provides a series of static methods to search, find and synchronize collections

4. Please briefly explain what is an iterator?

Iterator provides an interface for traversing and operating Collection elements, while the Collection interface implements the iteratable interface, that is, each Collection returns an instance of the iterator interface by implementing the iterator() method in the iteratable interface, and then iterates on the elements of the Collection.

5. Could you tell me the difference between Iterator and ListIterator?

Iterator can be used to traverse Set and List sets, but ListIterator can only be used to traverse List.

  • The Iterator can only remove() elements, while the ListIterator can add(), set(), remove()

  • Iterator can only use backward traversal in the order of next(), while ListIterator can traverse forward previous() and backward next()

    • There is also an additional function. ListIterator can use nextIndex() and previousIndex() to obtain the front and rear index positions of the current cursor position. Iterator does not have this function

5. Explain the similarities and differences between ArrayList, Vector and LinkedList

ArrayList and Vector

ArrayList is a main implementation class of List, and Vector is an outdated Java legacy container

  • Same: both of them use Object array to store data. Both of them can realize capacity expansion and allow direct query (index) of elements by serial number. However, inserting elements involves memory operations such as array element movement, so both query data quickly and insert data slowly

  • Different: Vector is a thread safe container because of the synchronized decoration added to the methods in Vector, but its performance is worse than ArrayList

ArrayList and LinkedList

  • Data structure: ArrayList is an Object array, and LinkedList is a two-way linked list (before JDK1.6, it was a circular linked list, and JDK1.7 canceled the cycle)

    • Query efficiency: ArrayList supports efficient random element access, that is, quickly obtain element objects through subscripts. The LinkedList does not support, so the query efficiency of ArrayList is higher

    • Addition and deletion efficiency: the bottom layer of ArrayList is array storage, so the time complexity of inserting and deleting elements is related to the position of element insertion, because it will involve the movement of elements. For example, if the addition is at the end, the time complexity is O(1). If the insertion is at the head, the time complexity is O(n). If the insertion is at any position in the middle, the time complexity is O((n - 1) / 2), The average time complexity is still O(n), while LinkedList uses linked list storage, so adding and deleting won't involve the movement of elements. You only need to modify the pointer. The time complexity can be simply seen as O(1). However, if you add or delete elements at a specified position, you need to move them to the specified position before inserting them. From this point of view, the time complexity is O(n)

  • Thread safety: ArrayList and LinkedListed are both non thread safe. If multiple threads operate on the same container, they can be converted into thread safe containers through the synchronizedList method in the tool class Collections before use (this is the application of decoration pattern, which passes an existing object into the constructor of another class to create a new object to enhance the implementation).

  • Memory consumption: each element of LinkedListed needs to store the addresses of the predecessor and successor nodes, so each element consumes more space, and ArrayList will reserve a certain capacity space as long as it is at the end. This is the case that the array cannot be fully filled due to capacity expansion (unless downsizing is used)

6. How to understand set disorder

Disorder means that the stored data is not added in the order of array index in the underlying array, but determined according to the hash value of the data.

7. How does HashSet check for duplicates

When you add an object to the HashSet, the HashSet will first calculate the hashcode value of the object to determine the location of the object. At the same time, it will also compare with the hashcode values of other added objects. If there is no matching hashcode, the HashSet will assume that the object does not appear repeatedly. However, if an object with the same hashcode value is found, equals() will be called Method to check whether objects with equal hashcodes are really the same. If they are the same, HashSet will not make the join operation successful.

8. Differences between HashMap and HashTable, HashSet, HashMap, etc

HashMap and HashTable

  • Data structure: HashMap JDK1.8 has made great changes in resolving hash conflicts. When the length of the linked list is greater than the threshold (8 by default), the linked list is converted to a red black tree to reduce the search time. However, it will be judged before converting to a red black tree. If the array length is less than 64, the array expansion will be given priority (the hash table hashes the keys, and the Map structure is that the mapping table stores key value pairs), while the HashTable does not have this special mechanism.

  • Thread safety: HashMap is non thread safe, while HashTable is thread safe (the method is decorated with synchronized). Therefore, HashMap efficiency will be slightly higher. It is generally considered that HashTable is similar to Vector, which is a Java legacy class and is basically not used. To ensure thread safety, consider using ConcurrentHashMap.

  • Null processing: both keys and values of HashMap can be stored as null types, but there can only be one key of null type, but there can be multiple values of null type. The key and value of HashTable are not allowed to have null type, otherwise a null pointer exception will be thrown.

  • Capacity expansion mechanism: when the initial value is not specified, the initial value of HashMap is 16. After each capacity expansion, the capacity will double the original value, and the initial value of HashTable is 11. Capacity expansion will make the capacity become the original 2n + 1. If the initial value is specified, HashMap will expand it to the power of 2, and HashTable will directly use the initial value you give.

HashMap and HashSet

  • HashMap implements the Map interface and HashSet implements the Set interface.

  • HashMap stores key value pairs, and HashSet only stores objects.

  • Use the put() method to put the element into the map and the add() method to put the element into the set, but the add() method actually calls the put() method in the HashMap.

  • HashMap uses the key object to calculate the hashcode value. HashSet uses the member object to calculate the hashcode value. For two objects, the hashcode may be the same, so the equals() method is used to judge the equality of objects. If the two objects are different, false is returned.

  • HashMap is faster because it uses a unique key to obtain objects, and HashSet is slower than HashMap.

HashMap and TreeMap

  • Order problem: the elements in HashMap have no order, and all the elements in TreeMap have a fixed order.

  • Thread safe: neither HashMap nor TreeMap is thread safe

  • Inheritance problem: HashMap inherits AbstractMap class; The hashcode() and equals() methods are overridden to ensure that two equal mappings return the same hash value. TreeMap inherits the SortedMap class and maintains the order of keys.

  • Tuning problem: HashMap is implemented based on hash table. hashcode() and equals() are clearly defined using the key classes required by HashMap (this method can be overridden); In order to optimize the space use of HashMap, you can tune the initial capacity and load factor. TreeMap is implemented based on the red black tree, so TreeMap has no tuning options, because the red black tree is always in a balanced state.

  • Applicable scenario: HashMap is applicable to Map insertion, deletion and positioning elements, and TreeMap is applicable to traversing key s in natural order or user-defined order.

9. Why is the length of HashMap to the power of 2

Because the underlying HashSet is implemented by hash table (linked list combined with array), the key obtains its position in the array through some operations during storage. We returned a hash value equivalent to its own value in the hashCoe method, but considering the range of int type data: - 2147483648 ~ 2147483647, it is obvious that these hash values cannot be used directly because there is no way to put a 4 billion length array in memory. Therefore, it uses the modulo operation on the array length, and then takes the remainder as its array subscript. indexFor() - in JDK7, it appears in this way, and indexFor() disappears in JDK8. All of them are replaced by the following statements. The principle is the same.

//In JDK8
(tab.length - 1) & hash;
Copy code
 //In JDK7
bucketIndex = indexFor(hash, table.length);

static int indexFor(int h, int length) {
    return h & (length - 1);
}
Copy code

It can be seen that the essential calculation methods are (length - 1) & hash. In a word, why do we use & instead of% in modular operation? Because bit operation directly operates on memory data and does not need to be converted to decimal, the processing speed is very fast, resulting in bit operation & efficiency much higher than modular operation%.

The most important thing is that if we use the more understandable remainder (%), length% hash = = (length - 1) & hash, the premise that the formula wants to hold must meet the n-th power of length 2

Simply put, the reason why the length of HashMap is to the power of 2 is that we use more efficient & operation instead of% operation, but we still use remainder operation to ensure the result of operation.

10. Briefly talk about the underlying principle in HashMap

Before JDK 1.8

Before JDK1.8, the bottom layer of HashMap is array + linked list. HashMap will use hashCode and perturbation function to process key, then obtain a hash value, and then judge the location where the current element should be stored through (length - 1) & hash. If there is an element in this location, judge whether the hash value and key of the element are the same as those of the element to be stored. If they are the same, Direct coverage. If it is different, the conflict is solved through the zipper method.

The disturbance function should be described clearly in 4.3

For the explanation of zipper method, you can also refer to 003 HashMap source code analysis (including hash table and red black tree introduction)

JDK 1.8

JDK 8 makes some major adjustments. When the length of the linked list in each grid in the array is greater than the threshold (8 by default), converting the linked list into a red black tree can greatly reduce the search time. However, it will be judged before converting to a red black tree. If the array length is less than 64, the array expansion will be given priority.

11. Understanding of loading factors in HashMap

  • The loading factor indicates the extent to which the elements in the hash table are filled. When there are too many elements in the table that exceed the value of the loading factor, the hash table will automatically expand, usually double. This behavior can be called rehashing.

  • The larger the value of the loading factor is set, the more elements will be added. Indeed, the space utilization has been greatly improved, but there is no doubt that the possibility of hash conflict increases. On the contrary, the space utilization causes waste, but the hash conflict is also reduced. Therefore, we hope to find an acceptable balance between space utilization and hash conflict, After some tests, it is set at 0.75f.

12. Differences between concurrent HashMap and Hashtable

Although HashTable also meets thread safety, it is similar to Vector. It is a Java legacy class and is basically not used. To ensure thread safety, consider using ConcurrentHashMap.

Data structure: in JDK 1.7, the bottom layer of ConcurrentHashMap is implemented by segmented array + linked list. In JDK 1.8, the data structure in ConcurrentHashMap is consistent with HashMap, which is array + linked list or red black tree. The Hashtable adopts the form of array + linked list (the array is the main body, and the linked list is used to solve hash conflicts)

Thread safety: in JDK 1.7, ConcurrentHashMap had a concept of segmented lock, that is, the whole array is divided (this is the concept of Segment). Each lock is only responsible for a part of the whole lock Segment. If multiple threads access the data of different data segments, the lock competition will not exist, and the access and law will be improved. In JDK 1.8, it is directly implemented with Node array + linked list or red black tree, and concurrency is controlled through synchronized (much optimized after JDK 1.6) and CAS. Hashtable uses a lock synchronized to ensure thread safety. The efficiency is not very high. Under multithreading, it is likely to fall into a blocking polling state.

  • Note: Although Segment can be seen in the source code of JDK 1.8, it is mainly for compatibility with the old version

7, Multithreading

1. The difference between concurrent, parallel and serial

Serial can not overlap in time. If the previous task is not completed, the next task can only wait

Parallel is overlapped in time, and the two tasks are executed at the same time without interfering with each other.

Concurrency allows two tasks to interfere with each other. At a unified time point, only one task runs and executes alternately

2. Processes and threads

A process is an application, and a thread is an execution path

The process has independent memory space, and the crash will not affect other programs,
  Threads do not have independent space. Multiple threads in the space of the same process may affect other threads
  There is at least one thread in a process

3. Multi thread creation method

Method 1: inherit Thread

  1. Create a subclass that inherits from the Thread class

  2. Rewrite the run() -- > of the Thread class to live the operation performed by this Thread in run()

  3. An object that creates a subclass of the Thread class

  4. Start the thread by calling the start() method from this object

The function of the start() method

  • Start the current thread

  • Call the run() method of the current thread

/**
 * Common methods of testing Thead:
 * 1,start(): Start the current thread; Call the run() of the current thread
 * 2,run(): You usually need to override this method in the Thread class and declare the operation to be performed by the created Thread in this method
 * 3,currentThread(): The static method returns the thread executing the current code, which is equivalent to the thread this alone
 * 4,getName(): Gets the name of the current thread
 * 5,setName(): Sets the name of the current thread
 * 6,yield(): Release the execution right of the current thread to the CPU and give it a chance
 * 7,join(): When thread a executes the join() method of thread b, it will give its own execution right to thread b. thread a will not start executing until thread b has finished executing. If there are three threads, which thread will block who is called
 * 8,stop(): End thread, method expired
 * 9,sleep(long millis): Let the thread sleep. The parameter specifies the time: milliseconds
 * 10,isAlive(): Determine whether the thread is alive
 */
class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0)
                System.out.println(Thread.currentThread().getName()+":"+i);
//            if (i % 20 == 0)
//                this.yield(); //yield == this.yield(), but direct yield() is no longer supported in java14
        }
    }

    public Thread1() {
    }
    public Thread1(String name) {
        super(name);
    }
}
public class ThreadMethodTest {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1("Thread:1");
//        thread1.setName("child thread 1");
        thread1.start();
        Thread.currentThread().setName("Main thread");
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 1)
                System.out.println(Thread.currentThread().getName()+":"+i);
            if (i == 40 ) {
                try {
                    thread1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Thread scheduling

  • scheduling strategy

    1. Time slice.

    2. Preemptive: high priority threads preempt CPU.

  • Java scheduling method

    1. Threads with the same priority form a first in first out queue (first in first out service) and use the time slice strategy.

    2. For high priority, the preemptive strategy of priority scheduling is used.

  • Priority level of the thread

    • MAX_PRIORITY: 10

    • Min MIN_PRIORITY: 1

    • Default NORM_PRIORITY: 5

  • Methods involved

    • getPriority(): return thread priority

    • setPriority(int new Priority): change the priority of the thread

  • explain

    1. When a thread is created, it inherits the priority of the parent thread

    2. Low priority is only a low probability of obtaining scheduling, not necessarily after high priority threads

Method 2: implement Runnable interface

**
 * Method 2 of creating multithreading: Implementation Runnable Interface
 * 1,Created and implemented Runnable Class of interface
 * 2,Implementation class to implement Runnable Abstract methods in: run()
 * 3,Create an object that implements the class
 * 4,Pass this object as a parameter to Thread Class, create Thread Class object
 * 5,adopt Thread Class start()
 *
 *   Mode 2 is equivalent to inheriting Thread Method of creating a thread Run Method take it out and put it Runnable In the interface,
 * And then after Runnable Put back Thread Start the thread to realize the second way of thread creation.
 *
 * Problem: threads thread start-up start()Why do methods use implementation interfaces Runnable Class of Runnable1 Medium run method?
 * A: check the source code==> Let's look from back to front and check first start()Method, we know start()The method is to use run()Method on,
 * So check Thread of run Method, get target Not for null Then call target of run()Method, and then view target The type of is Runnable,
 * Then look at the calls of the two classes and the threads created thread With parameters are used in runnable The construction method of the variable is known target The value of is the class Runnable1,
 *  So far we know Thread Class with parameters runnable The construction method of Runnable1 Assign to target,because target Not for null,
 *  So turn on the transmission Runnable1 of run method.
 *
 * Compare the two ways to create threads
 * Under development: priority: Implementation Runnable Interface mode
 * reason:
 *  1,The implementation method does not have the limitation of single inheritance of classes (the emergence of interfaces is to break the limitation of inheritance).
 *  2,The implementation method is more suitable to deal with the situation that multiple threads share data.
 *
 * Contact: Thread Also realize Runnable Interfaced
 * Same point: both methods need to be rewritten run(),Declare the logic to be executed by the thread in run()Method.
 *
 */
class Runnable1 implements Runnable{

    @Override
    public void run() {
        for (int i=1 ;i<=100; i++){
            if (i%2 == 0){
                System.out.println("Ergodic even"+i);
            }
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
        Runnable1 runnable1 = new Runnable1();
        Thread thread = new Thread(runnable1);
        thread.start();
    }
}

4. Thread life cycle

To implement multithreading, you must create a new Thread object in the main Thread. The Java language uses the objects of Thread class and its subclasses to represent threads. In its complete declaration cycle, the same city will experience the following five states

  • New: when the object of a Thread class or its subclass is declared and created, the new Thread object is in the new state.

  • Ready: after the thread in the new state is started (), it will enter the thread queue and wait for the CPU time slice. At this time, it has met the running conditions, but it has not been allocated CPU resources.

  • Run: when the ready thread is scheduled and obtains CPU resources, it is just like the running state. The run() method defines the operation and function of the thread

  • Blocking: in a special case, when the input / output operation is suspended or executed artificially, give up the CPU and temporarily suspend its execution to enter the blocking state.

  • Death: the thread has completed all its work, or the thread is forcibly terminated in advance or ends with an exception.

5. Thread synchronization

The real question: how to protect shared data?

resolvent:

When a thread a is operating a ticket, other threads cannot participate. When process a finishes operating the ticket, other threads can start operating the ticket. This situation cannot be changed even if thread a is blocked.

In Java, we solve the thread safety problem through synchronization mechanism.

Method 1: synchronize code blocks

It's very much like a toilet. Setting up a toilet certainly doesn't want anyone to break in, and then you need a lock. This lock can be a wooden stick, a stone, or even a book

synchronized(Synchronization monitor){
    //Code to be synchronized
}
//1. What is synchronized code? The code that operates shared data is the code that needs to be synchronized
//2. What is shared data? Variables operated by multiple threads. For example, a ticket is shared data, and judgment is also shared data
//3. What is a synchronization monitor? Synchronization monitor, commonly known as lock. The object of any class can act as a lock.
//		Lock requirements: multiple threads must share the same lock. (it's impossible to mark it with your own lock. This toilet is not used)

/**
 * Example: create three windows to buy tickets, a total of 100 tickets
 * There are safety problems to be solved:
 *      1,All three threads will sell the 100th ticket at the beginning
 *      2,Tickets cannot be sold in order
 *
 * 1,What is synchronized code? The code that operates shared data is the code that needs to be synchronized
 * 2,What is shared data? Variables operated by multiple threads. For example, a ticket is shared data, and judgment is also shared data
 * 3,What is a synchronization monitor? Synchronization monitor, commonly known as lock. The object of any class can act as a lock.
 * 4,In the way of implementing the Runnable interface to create multithreading, we can consider using this as the synchronization monitor
 *
 */
class windows implements Runnable {
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+": Ticket:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}
public class WindowTest {
    public static void main(String[] args) {
        windows windows = new windows();
        Thread thread1 = new Thread(windows);
        Thread thread2 = new Thread(windows);
        Thread thread3 = new Thread(windows);

        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}
Synchronous code block resolution inheritance Thread Thread safety issues for

package com.zhang.day02;

/**
 * Example: create three windows to buy tickets, a total of 100 tickets
 * There are safety problems to be solved:
 *      1,All three threads will sell the 100th ticket at the beginning
 *      2,Tickets cannot be sold in order
 *
 * Use synchronous code blocks to solve Thread safety problems by inheriting threads
 * The synchronization code block focuses on finding out whether the object is unique. If it is unique, lock the definition. If it is not unique, you need to use static
 * Synchronization code blocks cannot contain more or less
 *
 */
class windows2 extends Thread{
    private static int ticket = 100;
    //Since there are three objects created by inheriting Thread, static is used
    private static Object obj = new Object();
    @Override
    public void run() {
        while (true){
            //Reflection can be used to lock class < windows2 > windows2class = windows2.class; Reflection unique
            synchronized(obj){
                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+": Ticket:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

public class WindowTest2 {
    public static void main(String[] args) {
        windows2 w1 = new windows2();
        windows2 w2 = new windows2();
        windows2 w3 = new windows2();

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

    }
}

Mode 2: synchronization method

If the code that operates on shared data is completely declared in a method, we might as well synchronize this method declaration

1. The synchronization method solves the thread synchronization security problem of implementing Runnable interface

/** The synchronization method solves the thread synchronization problem of realizing Runnable interface
 * Example: create three windows to buy tickets, a total of 100 tickets
 * There are safety problems to be solved:
 *      1,All three threads will sell the 100th ticket at the beginning
 *      2,Tickets cannot be sold in order
 *
 * 1,The synchronization method is similar to the synchronization code block. The code to be surrounded by the synchronization method becomes method surrounded.
 * 2,It also has a lock, but its lock is this. This is the only one. It refers to windows 2 that inherits Runnable and implements multithreading.
 */
class windows2 implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            show();
            if (ticket <= 0)
            break;
        }
    }

    public synchronized void show(){
        if (ticket>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+": Ticket:"+ticket);
            ticket--;
        }
    }

}

public class WindowTest2 {
    public static void main(String[] args) {
        windows2 windows = new windows2();
        Thread thread1 = new Thread(windows);
        Thread thread2 = new Thread(windows);
        Thread thread3 = new Thread(windows);

        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

2. The synchronization method solves the Thread synchronization security problem of inheriting Thread

/**
 * Example: create three windows to buy tickets, a total of 100 tickets
 * There are safety problems to be solved:
 *      1,All three threads will sell the 100th ticket at the beginning
 *      2,Tickets cannot be sold in order
 *
 * Use the synchronization method to solve the Thread safety problem by inheriting the Thread
 *
 */
class windows4 extends Thread{
    private static int ticket = 100;
    @Override
    public void run() {
        while (true){
            if (ticket <= 0)
                break;
            show();
        }
    }

    private static synchronized void show(){
        //Because the lock in the synchronization method is this, and the object created by inheriting Thread to implement multithreading is not unique, the lock is not unique: w1 w2 w3
        //Solution: make the object they created unique and set the method to static, then the method lock is windows4.class
        if (ticket>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+": Ticket:"+ticket);
            ticket--;
        }
    }
}

public class WindowTest4 {
    public static void main(String[] args) {
        windows4 w1 = new windows4();
        windows4 w2 = new windows4();
        windows4 w3 = new windows4();

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

    }
}

Summary of synchronization method and synchronization method block

Synchronization solves the thread safety problem--- benefit

When operating synchronization code, only one thread can participate and other threads wait. It is equivalent to a single threaded process with low efficiency--- limitations

6. Deadlock

A shared resource will not deadlock, but most of the shared resources are multiple)

  • 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

/**
 * Demonstrate thread deadlock
 *
 * 1,Understanding of Deadlock: different threads occupy the synchronization resources required by each other and do not give up,
 * They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock.
 *
 * 2,explain:
 * 1)After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue
 * 2)When we use synchronization, we should avoid deadlock.
 *
 */

public class ThreadTest {
    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");
                    System.out.println("Waiting to get s2 lock");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(s2){
                        s1.append("b");
                        s2.append("2");
                        System.out.println("To get s2 Lock:"+s1);
                        System.out.println("To get s2 Lock:"+s2);
                    }
                }
            }
        }.start();

        new Thread(new Runnable(){
            @Override
            public void run() {
                synchronized(s2){
                    s1.append("c");
                    s2.append("3");
                    System.out.println("Waiting to get s1 lock");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(s1){
                        s1.append("d");
                        s2.append("4");
                        System.out.println("To get s1 Lock:"+s1);
                        System.out.println("To get s1 Lock:"+s2);
                    }
                }
            }
        }).start();
    }
}


//Demonstration of deadlock
class A{
    public synchronized void foo(B b){
        //When the main thread enters the synchronization method, the lock obtained by the main thread is a
        System.out.println("Current thread Name:"+Thread.currentThread().getName()+"Entered A Instance foo method");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Current thread Name:"+Thread.currentThread().getName()+"Attempt to call B Instance last method");
        //The lock required to call last with b is b
        b.last();
    }
    public synchronized void last(){
        System.out.println("Entered A Class last Method internal");
    }
}

class B{
    public synchronized void bar(A a){
        //The secondary thread calls the bar method with object b, and the set lock is b
        System.out.println("Current thread Name:"+Thread.currentThread().getName()+"Entered B Instance bar method");

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Current thread Name:"+Thread.currentThread().getName()+"Attempt to call A Instance last method");
        //The object passed is a, and the last method of a is used, so the lock is a
        a.last();
    }
    public synchronized void last(){
        System.out.println("Entered B Class last Method internal");
    }
}

/**So far we can know
 * Main thread: the init() method is called, and the init() method uses a to call the foo() method. foo() is a synchronous method and will use the called object a as a lock, so the foo() method obtains the a object lock
 *        foo()Method passes the parameter b object, and b calls the last() method. Since the last() method is also a synchronous method, he will use the calling object b as a lock,
 *        Therefore, the main thread starts to need a object as a lock and b object as a lock
 *
 * Secondary thread: the secondary thread starts the run() method and calls the bar() method with b. the bar() method is a synchronous method, so the b object is used as a lock
 *        bar()Method uses the transfer object b to call the last() method, and last() is also a synchronization method, so the a object is used as a lock
 *        Therefore, the secondary thread starts to need the b object as the lock, and the a object as the lock b
 *
 * So there is a deadlock problem
 * Question: how to see deadlock?
 * A: first, separate the main thread from the sub thread, one by one.
 *     Then find the lock. The synchronization method is to use the calling object as a lock. Static classes use the entire class as a lock.
 *     
 */
public class DeadLock implements Runnable{
    A a = new A();
    B b = new B();

    public void init(){
        //The main thread will enter this method
        Thread.currentThread().setName("Main thread");
        //Call foo method of a object
        a.foo(b);
        System.out.println("After entering the main thread");
    }

    @Override
    public void run() {
        //The secondary thread will enter this method
        Thread.currentThread().setName("Secondary thread");
        //Call the bar method of the b object
        b.bar(a);
        System.out.println("After entering the secondary thread");
    }

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

        dl.init();
    }
}

7.Lock

  • Interface is a tool that controls the access of multiple threads to shared resources. Locks provide exclusive access to shared resources. Only one thread can Lock the Lock object at a time. Threads should obtain the Lock object before accessing shared resources.

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

import java.util.concurrent.locks.ReentrantLock;

/**
 * Three ways to solve thread safety problems: Lock lock - JDK 5.0 NEW
 * 1,Interview question: what are the similarities and differences between synchronized and Lock?
 *      Same: both can solve the difficult problem of thread safety
 *      Difference: the synchronized mechanism automatically releases the synchronization monitor after executing the corresponding synchronization code
 *           Lock You need to manually start synchronization (Lock()), and you also need to manually implement (unlock()) to end synchronization
 *           (The understanding of the previous paragraph is more inclined to: because the lock is defined by the class first, and then the lock boundary is defined, the definition of the boundary needs to be opened and ended by methods,
 *           If synchronous methods are used, it is unnecessary to define the re call. Using synchronous method blocks to define boundaries is far less concise than using two methods to start and end,
 *           Therefore, I don't think that the idea of manual opening and ending causes the realization of the boundary defined by the two methods, but that the idea of defining the lock first and then defining the lock boundary causes the result of manual opening and ending.)
 *  Interview question: how to solve thread safety problems? How many ways? Three synchronization methods, synchronization block and Lock lock
 * Feelings: 1. Different from the synchronization method and synchronization method block, they will directly give the size of the toilet (code to be synchronized), as long as the code to be synchronized is put in,
 *      Lock Lock is to give priority to the code to be synchronized, use the code to determine the size, and then set the boundary of the toilet at the boundary of the code (that is, use the lock() and unlock() methods to determine the boundary of the code to be synchronized)
 *      2,Synchronization method and synchronization method block: one is to set the calling method, that is, this, as a lock, and the other is to define a lock by itself.
 *      Lock locks are similar to synchronization methods, except that lock locks raise the height to class, and synchronization methods are still methods. That is, a lock is defined as a class
 *      3,Therefore, we need to push to the previous inherent idea. Lock lock turns the lock into an interface, and ReentrantLock implements the interface, so it becomes a lock, and then it is defined using the lock
 *      The boundary that needs to be synchronized, that is, the toilet.
 *      contrast:
 *          Synchronization method and synchronization method block: set the toilet (the boundary of the code to be synchronized) first, and then lock it
 *          Lock Lock: first set the lock, and then use the lock to fix the toilet (the boundary of the code to be synchronized).
 *
 * Usage order: Lock - > synchronize code block (has entered the method and allocated corresponding resources) - > synchronize method (outside the method body)
 */
class Window implements Runnable{
    private int ticket = 100;

    //1. Instantiate ReentrantLock
    //Constructors with boolean values can be used. true means fair. It means first in first out in a queue. It means no contention. The default is false
    private ReentrantLock  lock=  new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                //2. Call the lock method lock()
                lock.lock();
                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"Ticket No.:"+ticket);
                    ticket--;
                }
            }finally {
                //3. Call the unlock method unlock()
                lock.unlock();
            }

        }
    }
}
public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

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

    }
}

Thread synchronization exercise 1

The bank has an account. Two depositors deposit 3000 yuan into the same account, 1000 yuan each time, three times. Print the account balance after each deposit.

Question: does the program have thread safety problems? If so, how to solve them?

Tips:

  1. Specify which codes are multi-threaded running codes, and write the run() method

  2. Clarify what shared data is.

  3. Specify which statements in multithreaded running code operate on shared data.

import java.util.concurrent.locks.ReentrantLock;

/**
 * The bank has an account.
 * There are two depositors who deposit 3000 yuan into the same account, 1000 yuan each time, three times. Print the account balance after each deposit.
 * analysis:
 *      1,Is it a multithreading problem? Yes, two depositor threads
 *      2,Is there shared data? Yes, account
 *      3,Is there a thread safety problem? Yes, we need to consider how to solve the thread safety problem. Synchronization mechanism: there are three ways
 *
 */
class Account{
    private int balance;
    private ReentrantLock Lock = new ReentrantLock(true);

    public Account(int balance) {
        this.balance = balance;
    }

    public void deposit(double amt){
        if (amt>0){
            Lock.lock();
            balance += amt;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"Deposit:"+amt+"Successful, balance:"+balance);
            Lock.unlock();
        }
    }

}
class Customer extends Thread{
    private Account account;

    public Customer(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            account.deposit(1000);
        }
    }
}



public class AcountTest {
    public static void main(String[] args) {
        Account account = new Account(0);
        Customer c1 = new Customer(account);
        Customer c2 = new Customer(account);
        c1.setName("Customer one");
        c2.setName("Customer II");

        c1.start();
        c2.start();
    }
}

8. Thread communication

When the wait() wait method is executed, the lock is released

Thread communication methods can only be used in synchronization methods or synchronization method blocks. lock locks are another word

Example: use two threads to print 1-100. Thread 1 and thread 2 print alternately

/**
 * Example of thread communication: use two threads to print 1-100. Thread 1 and thread 2 print alternately
 * Three methods involved:
 *      wait(): Once this method is executed, the current thread will enter the blocking state and release the synchronization monitor (i.e. lock) [key: wait will lose the lock]
 *      notify(): Once this method is executed, a thread that is waiting is awakened. If more than one thread is waiting, wake up the thread with higher priority [key: the thread that has been awakened can no longer be awakened, priority]
 *      notifyAll(): Once this method is executed, all one thread that is wait ing will be awakened. [all key points]
 * explain:
 *      1,wait(),notify(),notifyAll()The three methods must be used in the synchronization method or synchronization method block.
 *      2,wait(),notify(),notifyAll()The callers of the three methods must synchronize the method or lock in the synchronization method block
 *      3,Since objects, classes, etc. can act as locks, and the three methods wait(), notify(), notifyAll() are called with locks, where are the three methods defined?
 *      They are defined in the java.lang.Object class.
 * Interview question: what are the similarities and differences between sleep() and wait()?
 * 1,The same point: once the method is executed, the current thread can enter the blocking state.
 * 2,difference:
 *          1)Different declaration positions: the two methods declare different positions: sleep() in Thread class and wait() in Object class
 *          2)Different call locations: different call requirements: sleep() can be called in any required scenario. wait() must be used in synchronization code or synchronization methods
 *          3)Whether to release the synchronization monitor: if both methods are used in the synchronization code block or synchronization method, sleep() will not release the lock, and wait() will release the lock
 */


class Number implements Runnable{
    private int number = 1;

    @Override
    public void run() {
        while (true){
            synchronized(this){
                notify();

                if (number<=100){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+number);
                    number++;

                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else break;
            }
        }
    }
}

public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("Thread one");
        t2.setName("Thread two");

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

Classic example: Producer / consumer problem

The producer gives the product to the clerk, while the customer takes the product from the clerk. The clerk can only hold a fixed number of products at a time (e.g. 20). If the producer tries to produce more products, the clerk will ask the producer to stop. If there is an empty space in the store, the clerk will inform the producer to continue the production; If there is no product in the store, the clerk will tell the consumer to wait. If there is a product in the store, he will inform the consumer to take the product.

There may be two problems:

  • When producers are faster than consumers, consumers will miss some data.

  • When consumers are faster than producers, consumers will take the same data.

    /**
     * Application of thread communication: classic example: producer and consumer problems
     * The producer gives the product to the clerk, and the customer takes the product from the clerk,
     * The clerk can only hold a fixed number of products (e.g. 20) at a time. If the producer tries to produce more products,
     * The clerk will ask the producer to stop and inform the producer to continue production if there is a vacant place in the store;
     * If there is no product in the store, the clerk will tell the consumer to wait. If there is a product in the store, he will inform the consumer to take the product.
     *
     * analysis:
     *  1,Is it a multithreading problem? Yes, producer thread, consumer thread
     *  2,Is there shared data? Yes, product
     *  3,How to solve the thread security problem? Synchronization mechanism, there are three methods
     *  4,Is thread communication involved? yes
     *
     * Perception:
     *      1,When executing the while loop, you should realize that the two threads that join the synchronization lock will never terminate again,
     *      Only after consumption or production reaches 20 under extreme conditions can wait, which can be regarded as temporarily ending the program,
     *      Hand over the shared data to another thread for operation.
     *      2,Both methods are modified into synchronous methods with synchronized. Subconsciously, you will think that they are two locks. In fact, one lock is this
     */
    //clerk
    class Clerk{
        private int productCount = 0;
    
        public synchronized void produceProduct() {
            this.notify();
            if (productCount < 20){
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                productCount++;
                System.out.println(Thread.currentThread().getName()+": Production section"+productCount+"Products");
            }else {
                //The number of products is equal to 20. Let the consumer thread wait, and the consumer begins to consume the product
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public synchronized void consumeProduct() {
            this.notify();
            if (productCount > 0){
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+": Consumption section"+productCount+"Products");
                productCount--;
            }else {
                //When the number of products equals 0, the consumer thread waits and the producer starts producing products
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //consumer
    class Consumer extends Thread{
        private Clerk clerk;
    
        public Consumer(Clerk clerk) {
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            System.out.println("Consumers are consuming products.....");
            while (true){
                clerk.consumeProduct();
            }
        }
    }
    //producer
    class Producer extends Thread{
        private Clerk clerk;
    
        public Producer(Clerk clerk) {
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            System.out.println("The producer is producing products.....");
            while (true){
                clerk.produceProduct();
            }
        }
    }
    
    public class ProductTest {
        public static void main(String[] args) {
            Clerk clerk = new Clerk();
            Consumer c1 = new Consumer(clerk);
            Producer p1 = new Producer(clerk);
    
            c1.setName("Consumer 1");
            p1.setName("Producer 1");
    
            c1.start();
            p1.start();
        }
    }

Conclusion: it is not what I think. It must be carried out alternately, or the production must get 20, or the consumption must reach 0. Or I don't have to consider the process, but the direction. What kind of operation is required to connect to which node.

For example, after 20, you need to make the producer thread wait and wake up the consumer thread; When it reaches 0, you need to make the consumer thread wait and wake up the producer thread.

9. JDK5.0 new thread creation method

There are two ways to create new threads

New method 1: implement Callable interface

Callable is more powerful than Runnable

  • Compared with the run() method, you can have a return value

  • Method can throw an exception

  • Return values that support generics

  • You need to use the FutureTask class, such as getting the returned results

Future interface

  • You can cancel the execution results of specific Runnable and Callable tasks, query whether they are completed, obtain results, etc.

  • FutrueTask is the only implementation of the Future interface

  • FutureTask implements both Runnable and Future interfaces. It can be executed by the thread as Runnable or get the return value of Callable as Future

package com.zhang.day02;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * The third way to create a thread is to implement the Callable interface--- JDK 5.0 NEW
 * How to understand that the way to implement the Callable interface to create multithreads is more powerful than the way to implement the Runnable interface to create multithreads?
 * 1,call()You can return a value again
 * 2,call()Exceptions can be thrown and captured by external operations to obtain exception information
 * 3,Callable Is generic
 * 
 * Insight: in fact, implementing the Callable interface to create multiple threads is similar to that of Runnable. In fact, the interfaces inherited by Callable are Runnable and Callable,
 *      The Callable interface is implemented only to obtain the return value and throw an exception. So many operations are to use FutureTask to receive Callable objects,
 *      Start the thread with this object as a parameter, or use the get method to get the return value and its exception.
 */
//1. Create an implementation class that implements Callable
class NumberThread implements Callable{
    //2. Implement the call method and declare the operation to be performed by this thread in call()
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i%2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public class ThreadNew {
    public static void main(String[] args) {
        //3. Common Callable interface implementation class objects
        NumberThread thread = new NumberThread();
        //4. Pass the object of this Callable interface implementation class as a parameter to the FutureTask constructor to create the FutureTask object
        FutureTask<Integer> task = new FutureTask(thread);
        //5. Pass the FutureTask object as a parameter to the constructor of the Thread class, create the Thread object, and call the start method
        new Thread(task).start();
        try {
            Integer integer = task.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Insight: it's similar to the way to start threads by implementing the Runnable interface, just to obtain return values and exception functions. To use the Callable interface. In this way, the Callable object should be changed into a parameter and put into the constructor of FutureTask to obtain the FutureTask object. In this way, the FutureTask object can start the thread, obtain the return value, and handle the multifunctional operation of exceptions.

New method 2: use thread pool

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

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

Benefits:

  • Improved response time (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: how long does the thread last when there is no task, and then it will terminate

Thread pool related API

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

ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor

  • void executor(Runnable command): executes tasks / commands without return value. It is generally used to execute Runnable commands

  • Futuresubmit(Callable task): execute a task with a return value. It is generally used to execute Callable tasks

  • void shutdown(): closes the leveling pool

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

  • Executors.newCachedThreadPool(): create a thread pool that can create new threads as needed

  • Executors.newFixedThreadPool(n): create a reusable thread pool with a fixed number of threads

  • Executors.newSingleThreadExecutor(): create a thread pool with only one thread

  • Executors.newScheduledThreadPool(n): creates a thread pool that can schedule commands to run after a given delay or execute periodically

Thread pool create multithreading

package com.zhang.day02;

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

/**
 * Four ways to create threads: using thread pool
 *
 * Benefits:
 * - Improved response time (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: Size of core pool
 *   - maximumPoolSize: Maximum number of threads
 *   - keepAliveTime: When a thread has no task, how long will it last at most and then terminate
 *
 * Interview question: how many ways to create multithreading? Four!
 */
class NumberThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i%2 == 0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
class NumberThread2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i%2 != 0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {
        //1. Provides a thread pool for the specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);

        //Set the properties of the thread pool (because ExecutorService is an interface, there are no more operations, but its implementation class is required),
        //Therefore, we need to make a transformation, seize and give up our successors and get more methods
        //How to find this successor, we can use reflection search, because reflection is looking for classes, and above us is interfaces,
        //Using the interface to find the heir is equivalent to using the blood source to find the heir
        //System.out.println(service.getClass());
        ThreadPoolExecutor servie1 = (ThreadPoolExecutor) service;//Success in seizing and giving up

        //2. Performs the specified thread operation. You need to provide an implementation class object that implements the Runnable interface or Callable interface
        service.execute(new NumberThread1()); //Suitable for Runnable
        service.execute(new NumberThread2()); //Suitable for Runnable
        //service.submit();// For Callable
        //If you need to use the Callable interface to implement multithreading to receive parameters, use FutureTask to receive the return value of the submit() method, and the obtained object can be operated

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

Summary: the thread pool method is greatly reduced. The original two cumbersome steps of creating multithreads directly create a thread pool instead of creating multithreads one by one in new Thread().

Posted by nicob on Tue, 28 Sep 2021 18:52:45 -0700