Java Development Interview

  • 1. Deep copy and shallow copy
  • 2. The difference between interfaces and abstract classes
  • 3. How is Java memory allocated
  • 4. What are generics in Java? What is type erasure?
  • 5. What is reflection in Java
  • 6. Serialization and deserialization
  • 7. What methods does Object have?
  • 8.JVM memory model
  • 9. Class loading mechanism
  • 10. Object creation and object layout
  • 11.Java’s four types of references (strong, Soft, Weak, and virtual)
  • 12. Memory leaks and memory overflows
  • 13. The differences between List, Set and Map and their underlying data structures
  • 14. Four ways to create a thread
  • 15.NIO, AIO and BIO
  • Rewrite and reload
  • 17. The final/finally/finalize with static
  • 18. The difference between String, StringBuffer, and StringBuilder
  • 19. How to determine whether an object should be reclaimed?
  • Garbage collection algorithms
  • 21. A Double and Float
  • Garbage collector
  • 23. The thread pool
  • Thread synchronization and thread communication
  • 25. Interrupt threads
  • 26. The use of the Synchronized
  • 27. The principle of Synchronized
  • 28. The four states of Synchronized
  • 29. Differences between Synchronized and ReentrantLock
  • 30. Lock optimizations
  • 31.Java design pattern

Java:

1. Deep copy and shallow copy

There are stack areas and heap areas in memory. The basic type data is stored directly in the stack, while the reference type (new) is stored in the heap, and the address in the heap is stored in the stack. That is, instead of storing data on the stack, reference types store addresses. Assignment is just copying.

When assigning values to primitive data, there is no difference between light copy and dark copy, because the data is assigned directly.

However, when assigning a value to a reference type, you are actually copying the original address to the new one, so it is a shallow copy (the copy is not deep enough). When the new variable is used to manipulate the value in the address, the corresponding value of the old variable will also change. The clone method of Object in Java is shallow copy by default.

Deep copy creates another identical object. The new object does not share memory with the original object. Modifying the new object does not affect the old object.

Refer to the article

2. The difference between interfaces and abstract classes

  • Abstract class: modified by the abstract keyword. Abstract methods are also modified by abstract, with only method declarations and no method bodies.

  • Abstract classes cannot be instantiated, only inherited

  • Abstract classes can have properties, methods, and constructors, but constructors cannot be used for instantiation, and are mainly used to be called by subclasses

  • A subclass must implement abstract methods from an abstract class, or it must also be an abstract class

  • Abstract methods in abstract classes can only be public or protected

  • Interface: modified by the interface keyword.

  • Interfaces can contain variables and methods; Variables are implicitly set to public static final and methods are implicitly set to public Abstract

  • Interfaces support multiple inheritance, and one interface can extend multiple interfaces

  • A class can implement multiple interfaces

  • Jdk1.8 adds default and static methods: default/static

  • An interface can only be a definition of a function, and an abstract class can be either a definition of a function or an implementation of a function.

  • Neither an interface nor an abstract class can be instantiated. Implementation classes of an interface and subclasses of an abstract class can be instantiated only if they implement methods in the interface/abstract class.

  • The implementation interface keyword is implements, and the extension abstract class keyword is extends. A class can implement multiple interfaces, but a class can only inherit one abstract class.

  • Interfaces emphasize the implementation of specific functionality, while abstract classes emphasize ownership.

Refer to the article

3. How is Java memory allocated

Memory allocation is divided into stack allocation and heap allocation, most of which are reference types, so heap space is used more.

The objects are divided into young generation, old generation and permanent generation according to the survival time (method area).

Young generation: When an object is created, it is first assigned to the young generation. The young generation has three zones: Eden zone, Survivor 0 zone and Survive 1 zone. Most objects in Eden zone die quickly. Eden is a continuous memory space and memory allocation is fast. When Eden is full, Minor GC is performed to clean up dead objects and place surviving objects in survivor 0. Each time Minor GC is performed, the remaining surviving objects are placed in a non-empty Survivor zone. After survivor zone is full, It cleans up and moves to another survivor zone, which means that one survivor zone is always empty. By default, after 15 switches in the HotSpot VIRTUAL machine, objects that are still alive are placed in the tenured generation.


Aged generation: The aged generation usually has more space than the young generation and stores more objects. If the memory of the aged generation is insufficient, the Major GC (Full GC) is performed. If the object is large, it may be directly placed on the old generation. Java maintains a 512-byte block called “Card Table” that records the reference mapping. You can check the card table directly during Minor GC.

Refer to the article

4. What are generics in Java? What is type erasure?

To run Java source code, the compiler first compiles bytecodes, which store instructions that can be interpreted by the JVM to run. At run time, Java generics cannot obtain the true type of a type parameter because the bytecode generated by the compiler compilation does not include the specific type of the type parameter. Introduced after Java 1.5, generics are essentially parameterized types. That is, the type of a variable is a parameter that is specified as a specific type at the time of use. Generics can be used for classes, interfaces, and methods.

public class User<T> {
	
	private T name;
}// Generics actually pass in a type as an argumentThe type erasure mechanism makes Java generics in effect pseudo-generics, with type parameters only existing at compile time and the JVM unaware of the existence of generics at run time.public class ErasedTypeEquivalence {
  public static void main(String[] args) {
    Class c1 = new ArrayList<String>().getClass();
    Class c2 = new ArrayList<Integer>().getClass();
 System.out.println(c1 == c2); // The code output is true}}Copy the code

In languages like C++ and C# that support true generics, they represent different classes, but they are the same class to the JVM. Whenever a generic type is defined, the corresponding primitive type is automatically supplied, the type variable erased, and replaced with its qualified type (unqualified variables are replaced with Object). The Java compiler checks the code for generic types, erases them, and then compiles them. When the exact type is determined, generics provide a mechanism for type detection, so that only matching data can be assigned properly, otherwise the compiler will fail.

Refer to the article

5. What is reflection in Java

Java reflection is to map each component of a class into a Java object. During the runtime, any class can know the attributes and methods of this class. It is a method to dynamically obtain information and call objects.

  • Advantages: Dynamically load classes, improve code flexibility
  • Disadvantages: Reduces performance and may cause security problems

We use reflection in Spring/ Hibernate, using class.forname () to load the driver of the database through reflection when connecting to the database using JDBC. The Spring framework’s IOC (Dynamically loaded management Beans) creates objects, and AOP (dynamic proxies) are related to reflection.

6. Serialization and deserialization

  • Serialization: The process of converting Java objects into byte sequences.
  • Deserialization: Converts byte sequences into Java objects.

The Serializable interface is a signature interface that can be serialized, simply telling the JVM that an object of that class can be serialized. Let the serializable classes implement the Serializable interface first; The serialized object creates the output stream ObjectOutputStream, and then calls the writeObject() method; Deserialize the object create an input stream Obje ctInputStream, then call the readObject () method to get an Object object. Finally, close the stream.

7. What methods does Object have?

Equals: compares whether objects are equal. NotifyAll: Calling the wait method causes the thread to block, and releases the notify lock. NotifyAll: calling the notify method of the object randomly releases the blocked thread, and the thread retrieves the notifyAll lock. Wake up all threads that are waiting for an object and enter the lock pool to compete for lock wait,notify, and notifyAll must be used in synchronized method blocks. ToString: converts to a string representing getClass: returns an object runtime class, which is the reflection mechanism. HashCode: Converts the in-memory address of an object to an int value.

8.JVM memory model

Program counter (PC Register) : An indicator of the bytecode line number executed by a thread. The thread is private and the only area where there is no out-of-memory error.

  • Java virtual machine stackEach thread is created with a virtual stack, which holds a stack frame for each method call. The life cycle is the same as that of a thread. Holds local variables and partial results of a method and participates in method calls and returns. If the stack depth requested by the thread is greater than the depth allowed by the virtual machine, it is thrownStackOverflowThe exception; If the virtual stack can be dynamically extended, it is thrown if it is too extended to allocate sufficient memoryOutOfMemoryErrorThe exception.
  • Local method stack: Is similar to the virtual machine stack, but onlynativeMethod services.
  • The Java heap: thread shared memory, used to hold object instances, is the main area for garbage collection. The Java heap can be in a physically discontinuous memory space, as long as it is logically continuous, similar to disk space. Thrown if there is no memory in the heap for instance allocation and the heap can no longer be expandedOutOfMemoryErrorThe exception.
  • Methods area: thread shared memory is used to store data such as class information that has been loaded by VMS. It can be called a permanent generation or a meta-space. After JDK1.8, the data of a permanent generation is allocated to the heap and the meta-space, which stores class information, string constants, and a pool of runtime constants into the heap. Thrown if the method area cannot meet memory allocation requirementsOutOfMemoryErrorThe exception.

JVM tuning parameters

(1) -xMS: initializes heap memory. Default to 64th of physical memory (2) -Xmx: maximum heap memory. Default: quarter of physical memory (3) -xSS: size of a single thread stack (4) -XMN: size of a new generation (5) -xx: MetaspaceSize: size of a metadata space (6) -xx: SurvivorRatio: The default space ratio between Eden, S0 and S1 of the new generation is 8:1:1

JVM performance monitoring tool

(1) JPS -l: view the process number. (2) jStack: View the code with deadlocks and high CPU usage. (3) jinfo-flag: View the details of the parameter properties of the running Java program

9. Class loading mechanism

Class loading is the process of loading the class data from the class file into memory, validating, parsing, and initializing the class to form Java types that can be used by virtual machines.

The life cycle of a class: load, link, initialize, use, unload.

  1. Load: Fetch the binary byte stream by class name (through the class loader), place the static data structure in the method area, and generate the corresponding class object in memory as an access point.
  2. Link: Ensure that the current byte stream contains the information required by the virtual machine. Memory is formally allocated, initial values are set (only static variables are allocated), and symbolic references in the constant pool are replaced by direct references by the virtual machine.
  3. Initialization: The initialization phase is the execution of the class constructor methods, following the code logic that assigns real initialization values to the properties.
  4. Class loaders: includes the startup class loader, extension class loader, and application class loader.

10. Object creation and object layout

Object creation method:

Create with the new statement

To call the Clone method, you need to implement the Cloneable interface

Reflection: Class newInstance ()

Deserialization: Get a binary stream of an object from a file, using ObjectInputStream’s readObject method.

Object creation process:

Class load check: Determines whether the class has been initialized by the load link.

Allocate memory for objects: If the memory is neat, the VM uses the colliding pointer method (the pointer moves the size of the object forward to the free area). If not, use the free list method. Concurrency security: The VIRTUAL machine maintains a list of available memory blocks. During reallocation, the virtual machine finds a large enough space in the list to allocate to object instances and updates the list.

Initialize allocated space: all attributes are initialized to zero, ensuring that the object instance fields are available when not assigned

Set the object header information

Perform constructor initialization

Escape: An object created in a method body that has been referenced outside the method body by other variables. This way, objects created in the method cannot be collected by GC after the method completes execution. When escape analysis is enabled, if the scope of an object is only within a method, the object can be created on the virtual machine stack, created as the method goes on the stack, and destroyed as the method goes off the stack, reducing GC collection pressure.

Object memory layout: contains three parts: object header, instance data, and alignment padding.

Object header: Pointer to runtime data and type. Tag fields include hashcode, GC generation age, lock status flag, thread holding lock and other information. Pointer to class metadata: You know which class the object is an instance of.

Instance data: Stores the real data of the object, including the data of the parent class.

Align padding: Ensure that the object size is an integer multiple of 8 bytes.


11.Java’s four types of references (strong, Soft, Weak, and virtual)

Prior to JDK1.2, Java had a traditional definition of a reference: if the value stored in data of a Reference type was the starting address of another chunk of memory, that chunk of memory represented a reference.

  • Strong references: References declared by default in Java are strong references. As long as strong references exist, the garbage collector will never reclaim the referenced object, even if there is no memory, and the JVM will only throw an OOM error.
 Object obj = new Object();
Copy the code
  • Soft references: Used to describe objects that are not necessary but still useful. If the memory is insufficient, the system will reclaim the soft reference object. If the memory is insufficient, an OOM exception will be thrown. This feature makes it often used to implement caching techniques. After JDK1.2, usejava.lang.ref.SoftReferenceClass to represent a soft reference.
  • A weak reference: Weak references are weaker than soft references. Whenever the JVM starts garbage collection, objects associated with weak references are collected regardless of whether memory is sufficient. After JDK1.2, usejava.lang.ref.WeakReferenceTo represent weak references.
  • Virtual reference: The weakest reference relationship. Unlike the other types of references, virtual references do not determine the life cycle of an object; if an object holds only virtual references, it can be collected by the garbage collector at any time, just as if there were no references at all. Virtual references are primarily used to track the activity of objects being collected by the garbage collector and must be used in conjunction with reference queues. When the garbage collector is about to reclaim an object and finds that it has a virtual reference, it adds the virtual reference to the reference queue associated with it before reclaiming the object’s memory.

Refer to the article

12. Memory leaks and memory overflows

  • Memory leak: An object or variable that is no longer being used by a thread is still taking up space in memory.
  • Memory overflow: the program cannot allocate enough memory.

Cause of memory leak

1. Long-life objects hold references to short-life objects.

2. The connection is not closed.

3. The variable scope is too large

Avoiding memory leaks

1. Avoid creating objects in loops

2. Release useless objects as soon as possible

3. Be careful with static variables

4. The splicing of the string to use Stringbuffer/StringBuilder

5. Increase the XMX and XMS values

Cause of memory overflow

1. The loading data is too large

2. Dead loops or excessive loops

3. The memory value of the startup parameter is too small

Stack overflow

Cause: The recursion depth is too large and local variables are too large

Solution: Don’t recurse too deeply, change local variables to static ones

JConsole: displays the memory usage trend and determines whether there is a problem.GC logs: displays the configuration of the young generation and the old generation. 3. 4. Analyze the dump file: see the memory usage and thread status when OOM occurs

13. The differences between List, Set and Map and their underlying data structures

List: Ordered objects

(1) ArrayList (2) Vector (3) LinkedList (3

Set: Duplicate sets are not allowed

(1) HashSet (unordered and unique) : Based on HashMap (2) LinkedHashSet: Based on HashMap (3) TreeSet (ordered and unique) : based on red-black tree

Map: Use key-value pair storage

(1) HashMap: before Jdk1.8, HashMap consists of array + list. After that, when the list length exceeds the threshold (default 8), HashMap is converted to red-black tree to reduce search time. (2) LinkedHashMap: it inherits from HashMap, so its bottom layer is still based on the pulled hash structure, that is, it is composed of arrays and linked lists or red-black trees. In addition, LinkedHashMap adds a two-way linked list to the above structure, allowing the above structure to maintain the insertion order of key-value pairs. (4) TreeMap: The difference between ArrayList, LinkedList, and Vector

  • Storage structure:ArrayListandVectorIs implemented based on arrays, whileLinkedListIs based on bidirectional linked list implementation.
  • Thread safety:ArrayListNot thread safe (ArrayListThe operation of adding elements is not atomic, and it is possible to overwrite the value added by another thread.) in a single-threaded environment,LinkedListIt’s not safe. Vector is thread-safe and contains most of its keywordssynchronizedBut it is inefficient.
  • Expansion mechanism:ArrayListandVectorIt’s all arrays, and you can expand it when you run out of capacity,ArrayListThe capacity is 1.5 times that of the previous Vector, which is 2 times by default.VectorYou can set the expansion incrementcapacityIncrement. The principle of a variable length array is that when the number of elements exceeds the length of the array, a new array is generated, the data of the original array is copied to the new array, and the new elements are added to the new array.
  • Increase, delete, change and check efficiency:ArrayListandVectorIn, the time complexity of retrieving an object from a specified location or inserting and deleting an element at the end is O (1), but the time of adding and deleting an object at other locations is O (n);LinkedList, the time to insert or delete any position is O (1), but the time to retrieve an element is O (n).

14. Four ways to create a thread

Thread classes that inherit Thread can no longer inherit from other parent classes.

Implement the Runnable interface, rewrite the run method

Create a thread through the Callable and Future interfaces, execute the Call method, and return a value to throw an exception

The thread pool. The first three types of threads can consume system resources and affect performance if they are created and closed frequently, while using a thread pool can be put back into the thread pool when it is not used and retrieved from the thread pool when it is used.

15.NIO, AIO and BIO

BIO: Traditional network communication model, synchronous blocking IO. The server implementation is a connection thread, when the client has a connection request, the server has to start a thread to process. The number of threads may explode and crash. Suitable for architectures with a small number of fixed connections. NIO: Synchronous non-blocking. Server implementation is a request a thread, the client sent connection requests are registered with the multiplexer, multiplexer polling until the connection has IO requests to start the thread. This applies to architectures with a large number of short connections, such as chat servers. AIO: asynchronous non-blocking. The user process only needs to initiate an I/O operation and then return immediately. When the I/O operation is complete, the application is notified that the I/O operation is complete. This applies to architectures with a large number of connections and long connections.

Rewrite and reload

Override: A subclass rewrites the method implementation that the parent class allows access to. The return value and parameter cannot be changed. The nice thing about overrides is that subclasses can define specific behaviors based on specific needs. The range of exceptions can be reduced, but new or broader exceptions cannot be thrown.

class Animal{
   public void move(a){
      System.out.println("Animals can move"); }}// Join Java development chat
class Dog extends Animal{
   public void move(a){
      System.out.println("Dogs can run and walk."); }}public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); / / Animal object
      Animal b = new Dog(); / / Dog
// Join Java development chat
      a.move();// Execute the Animal class method
      b.move();// Execute the Dog class method}}Copy the code

Although B is Animal, it runs the Dog class move method. Because only the reference type of the parameter is checked at compile time, the runtime JVM specifies the type of the object and runs its methods. Method rewriting rule

  • (1) The argument list and the argument list of the overridden method must be exactly the same.

  • (2) Access cannot be lower than that of the overridden method in the parent class.

  • (3) A member method of a parent class can only be overridden by its subclasses.

  • (4) Methods declared final cannot be overridden; Methods declared static cannot be overridden, but can be declared again.

  • (5) The constructor cannot be overridden.

  • (6) If the subclass and its parent are in the same package, the subclass can override methods that are not declared private and final in the parent class. If not in the same package, subclasses can override only non-final methods declared public and protected by their parent class.

Use the super keyword when you need to call the overridden method of the parent class in a subclass.

Overload: Two methods with the same name and different arguments in the same class. The return types can be the same or different. Each overloaded method (or constructor) must have a unique list of parameter types. Often used to construct heavy loads.

Overloading rules

(1) Overloaded methods must change the argument list. (2) Overloaded methods can change return types, can change access modifiers, and can declare new or more extensive exception checking. (3) Methods can be overridden in the same class or in a subclass.

public class Overloading {
    public int test(a){
        System.out.println("test1");
        return 1;
    }
 
    public void test(int a){
        System.out.println("test2");
    }   
 // Join Java development chat
    // The following two parameters are in different order
    public String test(int a,String s){
        System.out.println("test3");
        return "returntest3";
    }   
 
    public String test(String s,int a){
        System.out.println("test4");
        return "returntest4";
    }   
 
    public static void main(String[] args){
        Overloading o = new Overloading();
        System.out.println(o.test());
        o.test(1);
        System.out.println(o.test(1."test3"));
        System.out.println(o.test("test4".1)); }}Copy the code

Method overloading and method overwriting are different manifestations of Java polymorphism. Refer to the article

17.Final/finally/finalize with static

  • final: A keyword or modifier in Java. If a class is declared asfinal, which means that it cannot be subclassed or inherited as a parent class. A class cannot be declared simultaneouslyThe final and the abstractAn abstract class. If a variable or method is declared asfinalVariables must be assigned at declaration time. Subsequent references are read only. Methods declared final can only be used and cannot be overloaded.
  • finally: a Java exception handling mechanism. The best addition to the Java exception handling model,finallyStructure makes code always execute, regardless of whether exceptions occur. You can use finally to maintain the internal state of an object and clean up non-memory resources. When closing the database connection, if the database connectionclose()Putting methods in finally reduces the chance of errors.
  • finalize: The name of a Java method that does the necessary cleanup before the garbage collector purges an object from memory. This method is called when the garbage collector determines that the object is not referenced. It’s inObjectClass, so all classes inherit it. Subclasses can override this method to collate resources and clean up.
  • staticStatic modifier properties can be initialized by the compiler and changed after initialization. Final modifier properties can be initialized by the compiler or at runtime but cannot be changed.staticLocal variables cannot be decorated, butfinaL can.

18. The difference between String, StringBuffer, and StringBuilder

String is widely used in Java programming, but its underlying implementation is actually a character array of final type, whose values are immutable, and each operation on String generates a new object, resulting ina waste of memory.

private final char value[];
Copy the code

StringBuffer/StringBuilder: they are variable to the bottom of a character array, inherit AbstractStringBuilder abstract class and so on frequent string manipulation, try to use these two classes, the difference is: StringBuilder is thread-unsafe but fast to execute; Stringbuffers are thread-safe but slow to execute. StringBuffer uses the synchronized keyword for locking. In addition, String comparison, “==” compares whether two memory addresses are the same, and “equals” compares whether two String values are the same. Refer to the article

19. How to determine whether an object should be reclaimed?

Reference counting algorithm: adds a reference counter to an object. When a reference is added to an object, +1, the reference is invalid -1, and the object with a reference count of 0 can be reclaimed. But in the case of two objects referencing each other, the counter is never zero, so the JVM does not use a reference-counting algorithm. Reachable analysis algorithm: Search starts with GC Roots, reachable objects are all alive, and unreachable objects can be recycled. JVM uses this algorithm for judgment. GC Roots contains: objects referenced in the virtual machine stack, objects referenced in the local method stack, and objects referenced by static members or constants in the method area.


Garbage collection algorithms

Mark-sweep algorithm

Marking stage: The marking process is actually the process of reachable analysis algorithm, traversing GC Roots objects, marking all reachable objects and recording them as reachable in the header of objects.

Cleanup phase: The heap is traversed, and if an object is found without reachable object markers, it is recycled.

Disadvantages: two traversal, low efficiency; The whole program needs to be stopped when GC runs; A large number of fragments are generated and a free list needs to be maintained.

Each time a Copying object passes through a Minor GC in a Survivor region, it ages the object +1, and when it reaches a certain age, it copies the object to the old age, which defaults to 15. The default ratio of Eden to Survivor space in the JVM is 8:1:1, ensuring 90% memory utilization. If more than 10% of the objects in each collection survive, Survivor space may run out and the old era space is borrowed.

Disadvantages: The copy-collection algorithm needs to carry out a lot of replication operations when the object survival rate is high, and the efficiency will be low. Generally, this algorithm is not used in the old era.

Mark-collation algorithm

The first stage is the same as the mark-clear algorithm, and the second stage compresses all surviving objects to the other end of memory, discharging them in sequence. After that, clean up all the space outside the boundary. Disadvantages: low efficiency, not only to mark the live object, but also collate all the live object reference address; Pause the user application throughout the movement. Generational collection algorithm

New generation: Use the copy algorithm because a large number of objects need to be recycled. In the old days: There are few objects to recycle, so we use the tag cleanup or tag cleanup algorithm.

21. A Double and Float

The Java language supports two basic floating point types: float and double. The 32-bit floating-point number float has 1 bit for symbol, 8 bits for exponent, and 23 bits for mantissa; The 64-bit floating-point number double uses one bit for the symbol, 11 bits for the exponent, and 52 bits for the mantissa. Float is automatically rounded to more than 23 bits. That’s the precision limit of float, so double can be represented and float can’t be exact. If you want to convert these two floats, Java provides float.doubleValue () and double-.floatValue () methods. When using this method, there will be deviations from single precision to double precision. Floating-point operations are rarely accurate, and errors occur whenever they exceed the range of precision representations.

Solution: The conversion can be done by String in conjunction with BigDecimal or by using the long type.

Refer to the article

Garbage collector

View the default garbage collector: -xx :+PrintCommandLineFlags

  • Serial Serial collectorIn the Client mode, the default garbage collector is the new generation garbage collector. The new generation garbage collector uses the replication algorithm, and the Old generation uses the tag collation algorithm. Serial Old is also used as the backup garbage collection solution for the CMS collector. JVM parameters: -xx :+UseSerialGC
  • ParNew collector: Multithreaded version of Serial, corresponding to the JVM argument: -xx :+UseParNewGC. When parameters are turned on, a combination of the ParNew copy algorithm and the Serial Old tag collation algorithm is used, which is no longer recommended after Java8.
  • Parallel avengeThe Parallel Avenge can be used by both the new generation and the old generation to set optimization goals for a virtual machine using an adaptive adjustment strategy that sets up basic memory data and focuses on maximum downtime or throughput. The JVM arguments are: -xx :+UseParallelGC. The new generation uses the copy algorithm and the old generation uses the mark-collation algorithm.
  • CMS collector: a collector whose goal is to obtain the shortest collection pause time. JVM parameters: -xx :+UseConcMarkSweepGC. The collector combination of ParNew +CMS +Serial Old is used. The advantage is concurrent collection with fewer pauses. The disadvantages are that concurrency can strain the CPU, and marker clearing algorithms can generate a lot of space debris.

(1) Initial mark: Mark objects that GC Roots can be directly associated with, which is fast and requires a pause. (2) Concurrent tagging: Go to GC Roots Trancing without stopping. (3) re-marking: during the correction of concurrent marking, the part of the object that is changed due to the continued operation of the user program is re-marked, which requires a pause. (4) Concurrent cleanup: no need to pause.

G1 garbage collector: It causes memory regions such as Eden, Survivor, and Tenured to cease to be contiguous and become regions of the same size, each ranging from 1M to 32M. Instead of using CMS’s tag cleaning algorithm, G1 uses the tag cleaning algorithm as a whole and is locally based on the copy algorithm. JVM parameters: -xx :+UseG1GC.

Reducing pause times is a common focus of G1 and CMS, but G1 can also model predictable pause times, allowing users to specify a time slice of M milliseconds in length. This is because the G1 collector maintains a priority list behind the scenes, each time choosing the region with the greatest collection value based on the allowed collection time. Win10: Create a new variable JAVA_OPTS in the environment variable and set it inside.

23. The thread pool

Creating a thread while using threads is very simple, but causes a problem: if there are many concurrent threads, and each thread completes a short task, creating threads frequently can greatly reduce system efficiency.


Thread pooling was introduced in Java to make threads reusable, allowing them to continue to perform other tasks instead of being destroyed immediately.

The ThreadPoolExecutor class is at the heart of thread pool technology:

Parameter meaning in its constructor

  • corePoolSize:Core pool size. After the thread pool is created, there are no threads in the default thread pool unless calledprestartAllCoreThreads()orprestartCoreThread()Method to create a thread before the task arrivescorePoolSizeA thread. When the number of threads in the thread pool reachescorePoolSizeAfter that, the incoming task is put into the cache sequence.
  • maximumPoolSize: very important parameter that indicates the maximum number of threads that can be created in the thread pool.
  • KeepAliveTime:Indicates the maximum length of time a thread can hold without executing a task before terminating.
  • unitParameters:keepAliveTimeA unit of time.
  • WorkQueue:Blocking queues, which store tasks waiting to be executed, can have a significant impact on the running of thread pools. There are three options:ArrayBlockingQueue,LinkedBlockingQueueandSynchronousQueue, generally use the latter two.
  • threadFactory: thread factory, used to create threads.
  • handler: indicates the policy for rejecting tasks. The value can be:

(1) ThreadPoolExecutor. AbortPolicy: discard task thrown RejectedExecutionException exception; (2) the ThreadPoolExecutor. DiscardPolicy: discard task, don’t throw exception. (3) the ThreadPoolExecutor DiscardOldestPolicy: Discarding the queue in front of the task, and then to try to perform a task (repeat the process). (4) ThreadPoolExecutor CallRunsPolicy: handle the tasks by the calling thread

Method of the ThreadPoolExecutor class

Execute () and submit() : both submit tasks. The execute method is used to submit tasks that do not need to return values. It is impossible to determine whether the task is successfully executed by the thread pool. Submit submits the task that needs to return a value. The thread pool returns an object of type Future to determine whether it has executed successfully. The Future object has a get() method that can get the return value. `

Shutdown () and shutdownNow() : both shutdown the thread pool. They work by iterating through the pool of worker threads and then interrupting them one by one by calling interrupt methods, so tasks that cannot respond to interrupts may never be terminated. ShutdownNow first sets the state of the thread pool to STOP, then attempts to STOP all executing or paused threads and returns a list of tasks awaiting execution. Shutdown simply sets the state of the thread pool to shutdown, and then interrupts all threads that are not executing.

How to properly allocate the size of the thread pool: CPU intensive tasks, the general formula is: maximum number of threads = NUMBER of CPU cores +1; Maximum number of IO – intensive threads = number of CPU cores x 2.

Implement a thread pool:

public class Test {
     public static void main(String[] args) {   
         ThreadPoolExecutor executor = new ThreadPoolExecutor(5.10.200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
          
         for(int i=0; i<15; i++){ MyTask myTask =new MyTask(i);
            executor.execute(myTask);
            System.out.println("Number of threads in the thread pool:"+executor.getPoolSize()+", number of tasks in the queue waiting to execute:"+
            executor.getQueue().size()+", number of other tasks completed:+executor.getCompletedTaskCount()); } executor.shutdown(); }}Copy the code

Thread pools cannot be created by using the static method of Executors. You must go through ThreadPoolExecutor.

When a thread pool submits a task: (1) the thread pool to judge the core threads in the pool is on a mission, if not, create a new worker thread to perform a task, or into the process (2) and (2) the thread pool to determine whether a work queue is full, if there is no full will submit new task stored in the task queue, if the job queue is full, Then enter the thread pool of process (3) (3) to determine whether all the threads in the pool are working. If not, create a new worker thread to execute the task. If it is full, hand it to the rejection policy (handler) to handle the task. Refer to the article

(1) newCachedThreadPool Creates a cacheable thread pool. (2) newFixedThreadPool creates a fixed length thread pool, which can control the maximum number of concurrent threads. (3) newScheduledThreadPool Creates a thread pool of fixed length that supports scheduled and periodic task execution. (4) newSingleThreadExecutor creates a single threaded thread pool, which only uses a single worker thread to execute tasks, ensuring that all tasks are executed in the specified order.

// A thread pool that can be cached
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // Specify the length
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
Copy the code

Detailed implementation code

Thread synchronization and thread communication

There are five ways of thread synchronization: synchronized keyword modification methods, static resources or code blocks; Lock (must be executed in try-catch-finally, finally releases the Lock to prevent deadlocks); “Wait” and “notify” must be synchronized. Synchronized locks the object that calls “wait” and “notify”. The CAS. Semaphore.

How threads communicate:

  • (1)Wait (), notify(), nofityAll(): Wait/notification mechanism. Thread A calls object O’swaitMethod enters the wait state, and another thread B calls O’snotifyornotifyAllMethod after thread A receives A notification from object OwaitMethod to perform subsequent operations. Calling the wait method on an object causes the thread to block, releasing the lock on the object. Calling the notify method of an object randomly releases the blocked thread of the object, which tries to acquire the lock again. A wait method returns only if the lock of the calling object is acquired; Must be insynchronizedBlock or method.
  • (2)condition:Conditionwithawait(),signal.singalAllMethods to replaceWait and notify.notifyCan only wake up one thread at random, but withconditionCan wake up the specified thread.
  • (3) Pipelines
  • (4) the volatile
  • (5)Thread.join: If a thread executesThread.join(), meaning that the current thread A waits for thread A to terminatethread.join()To return.

25. Interrupt threads

Call the interrupt() method of a thread to interrupt it, and if the thread is in a blocking, finite wait, or indefinite wait state, InterruptedException is thrown, terminates the thread prematurely.

If a thread’s run() executes an infinite loop and does not perform an operation such as sleep() that throws InterruptedException, calling interrupt() will not cause the thread to terminate prematurely. Calling interrupt sets the Thread’s interrupt flag, and calling thread.interrupted () or Thread.currentThread().isinterrupted () returns true. Therefore, you can use the interrupted() method in the loop body to determine if the thread is interrupted and terminate it early.

26. The use of the Synchronized

Thread safety is the focus of Concurrent programming in Java. There are two main reasons for thread safety problems: one is shared data; the other is shared data operated by multiple threads. Therefore, when multiple threads operate the shared data, only one thread must operate the shared data at the same time, and other threads must wait until the thread finishes processing the shared data. This mode is called mutex. In Java, the synchronized keyword ensures that only one thread can execute a method or block of code at any one time, and that changes made by one thread (sharing data) are visible to other threads (visibility assurance, a complete substitute for Volatile).

Synchronized is a Java keyword and a type of synchronization lock.

Java’s synchronized: Each Java object can be used as a lock to achieve synchronization. These locks are called synchronized. The lock is automatically acquired when a thread enters a synchronized block or method, and released when it exits the synchronized block. The only way to get a built-in lock is to enter the synchronized code block/method protected by the lock.

Java object and class locks: Locks are the same concept as built-in locks, but object locks are used on object instance methods or object instances. Class locks are used on static methods of a class or on a class object.

Each object in Java has a lock and two queues, one for suspending threads that have not acquired the lock, and one for suspending threads that are waiting if the condition is not met. Synchronized is really an integration of locking and releasing locks. The JVM is responsible for keeping track of how many times an object is locked. If an object is unlocked, the count returns to zero. The first time a thread locks an object, the count becomes 1. The count is incremented each time the same thread acquires a lock on the object. Each time a task leaves a synchronized method, the count decays, reaching zero when the lock is fully released.

Synchronized can be used in three ways:

Accessorize an instance method: The accessorized method is called an instance-synchronized method and is scoped to the entire method, locking the object that the method belongs to (the object that called the method). The object is locked by all operations that need to acquire it.

  public synchronized void method(a){}
  / / is equivalent to
  public void method(a){
    synchronized(this) {}}Copy the code

If an object has multiple synchronized methods, as long as one thread accesses one of the synchronized methods, no other thread can access any synchronized methods in the object at the same time. When an object O1 executes this synchronized method in different threads, it is mutually exclusive. But O2, another object of O1’s class, can call the synchronized method. Other threads calling the same method in O2 do not cause synchronous blocking. In this case, the program may escape the control of the synchronization mechanism, resulting in data chaos. Note:

  • (1)synchronizedKeywords are not inherited: subclasses override the parent bandsynchronizedMethod must also explicitly add the synchronized keyword to the subclass method.
  • (2) Do not use synchronized keyword when defining an interface.
  • (3) The constructor cannot use the synchronized keyword, but can use the synchronized code block to complete synchronization.

Modify a static method: The method being modified is called a statically synchronized method, whose scope is the entire static method and whose lock is the class to which the static method belongs.

 public synchronized static void method(a){} modifies code blocks: The code blocks being modified are called synchronous blocks. Synchronized parentheses must pass in an object as a lock, the scope is the code in curly braces, the lock is the content of synchronized parentheses, can be divided into class lock and object lock// Lock objects are instance objects
 public void method(Object o){ synchronized(o){ ... }}// Join Java development chat
The lock object is the Class object of the Class
 public class Demo{
   public static void method(a){ synchronized(Demo.class){ ... }}}Copy the code

27. The principle of Synchronized

It’s actually through the monitor. Synchronized code blocks in Java are implemented using monitorenter and Monitorexit directives, where monitorenter inserts at the beginning of the synchronized code block and Monitorexit inserts at the end of the synchronized code block.

The JVM guarantees that these two instructions come in pairs. When monitorenter executes, the thread attempts to acquire the lock, or ownership, of the Monitor object, which is acquired when the counter is 0 and incremented by one. After monitorexit, decrease the lock counter by one to indicate that the lock is released. The monitorenter and Monitorexit directives are replaced by the ACC_SYNCHRONIZED identifier, which identifies the synchronized method as a synchronized method.

28. The four states of Synchronized

No lock –> Bias lock –> Lightweight lock –> Heavyweight lock (irreversible)

Biased locks: In most cases, locks are not contested by multiple threads and are always acquired multiple times by the same thread. If a thread acquires a lock, the lock goes into bias mode, and the Mark Word structure of the object header changes to bias lock.

Object headers were mentioned in Chapter 10, and this article goes into more detail. When the Thread requests the lock again, it only needs to check whether the Mark Word lock is marked as biased lock and whether the current Thread ID is equal to the Mark Word Thread ID, saving a lot of operations related to lock application. Biased locking applies only to scenarios where only one thread accesses a synchronized block.


Lightweight lock: When a biased lock is accessed by another thread, the biased lock is upgraded to lightweight. The other thread attempts to acquire the lock through spin without blocking, thus improving performance. Suitable for the pursuit of response time, synchronization fast execution speed is very fast.

When the code enters the synchronization block, if the synchronization object Lock state is no Lock, the virtual machine first creates a Lock Record space in the stack frame of the current thread, and copies the Mark Word of the object header into the Lock Record.

The VIRTUAL machine then uses the CAS operation to try to update the object’s Mark Word to a pointer to the Lock Record, and set the owner pointer of the Lock Record to the object’s Mark Word. If this action succeeds, the thread has the lock on the object, which is marked “00”, indicating a lightweight lock.

If this action fails, the JVM checks if the object’s Mark Word points to the current thread’s stack frame. If it does, the current thread already owns the lock on the object. If it does not, multiple threads compete for the lock.

If there are more than two threads competing for the same lock, the lightweight lock is no longer valid and expands to the heavyweight lock.


Heavyweight locks: In multi-threaded situations, threads block with slow response time, and frequent release and acquisition of locks can cause significant performance loss. It is suitable for the scenario of fast synchronization and long execution speed in pursuit of throughput.

29. Differences between Synchronized and ReentrantLock

In contrast to ReentrantLock, synchronized locks are heavyweight and built-in, meaning that the JVM can optimize them. Threads that block on a synchronized lock are non-interruptible, whereas ReentrantLock implements interruptible blocking.

Synchronized lock release is automatic, whereas ReentrantLock requires explicit release (ina try-finally block) \

It is unfair for threads to compete for synchronized locks: if the synchronized lock is occupied by thread A, thread B fails to request and is put into the queue. Thread C requests the lock at this time, and when THREAD A releases the lock at this time, thread C will directly obtain the lock by skipping thread B waiting in the queue. ReentrantLock, however, can make locking fair.

Synchronized locks are mutually exclusive to read/write. ReentrankWriteLock is divided into read locks and write locks. Read locks can be held by multiple threads at the same time and are suitable for concurrent scenarios in which more reads and less writes are used.

ReentrantLock can only lock code blocks, whereas synchronized can lock methods and classes. ReentrantLock can tell if a thread has acquired the lock, but synchronized cannot.

Reference article on synchronized

30. Lock optimizations

In section 28, we talked about heavyweight locks. In heavyweight locks, the JVM blocks threads that have not acquired the lock and wakes them up when the lock is released. Blocking and awakening are operating system dependent and require an expensive switch from user to kernel mode. Monitor calls mutex, the underlying OS, and the switching costs are high. So the JVM introduced the concept of spin.

Spin-lock and adaptive spin-lock, CAS implementation:

  • spinlocks: In many cases, the locked state of shared data is short-lived and it is not worth switching threads; By having a thread execute a busy loop to wait for the lock to be released, the CPU is not freed. The disadvantage is that if the lock is held by another thread for a long time, it incurs a lot of overhead.
  • Adaptive spin lock: The number of spins is not fixed and is determined by the previous spin time on the same lock and the status of the lock owner.
  • advantages: The spin lock does not change the thread state. It is always in user state and does not block the thread. The execution speed is fast.
  • CAS(Compare And Swap) Optimistic And pessimistic locks: Synchronized is a pessimistic lock. Once a thread obtains the lock, other threads that need to be locked are suspended. CAS operations are actually optimistic locks, each time an operation is completed without locking, assuming no conflicts, and if it fails, retry until it succeeds. Pessimism is the belief that the concurrency in the program is severe, and optimism is the belief that the concurrency is not so severe that multiple attempts can be made.
  • Lock elimination: The virtual machine removes locks that require synchronization on code when the just-in-time compiler is running and detects that there is no real possibility of competing for shared data. The rationale is that the JVM determines that synchronization in a program is obviously not going to escape and be accessed by other threads, and the JVM treats it like data on the stack that is unique to the thread.
  • Lock coarsening: When adding synchronization locks, we try to limit the scope of the synchronization block to a small scope. However, if there are a series of operations that repeatedly lock and unlock the same object, or even if the lock occurs in the loop body, frequent mutex synchronization can cause consumption even if there are no competing threads.
public static String test04(String s1, String s2, String s3) {
        StringBuffer sb = new StringBuffer();
        sb.append(s1);
        sb.append(s2);
        sb.append(s3);
        return sb.toString();
    }
Copy the code

This is the case for successive Append operations. When the JVM detects that a series of operations are locking the same object, it extends the lock synchronization scope (coarser) to the outside of the entire series of operations, so that a series of Appends only need to be locked once.

31.Java design pattern

Design patterns are a set of commonly used, well-understood, catalogued code design lessons. Design patterns are used to make code reusable and easier for others to understand. It’s really a generic solution to a certain kind of problem in certain scenarios. Design patterns fall into three categories:

  • (1) Creation mode: the mode of object instantiation. The creation mode is used to decouple the object instantiation process. Including singleton pattern, simple factory, abstract factory and so on.
  • (2) Structural pattern: combine classes and objects together to form a larger structure. These include adapter mode, composite mode, decorator mode, and so on.
  • (3) Behavioral pattern: how classes and objects interact, and divide responsibilities and algorithms. This includes template mode, interpreter mode, observer mode, and so on.

Singleton mode: the creation mode can be written in three ways: slacker, hunker, and register.

Singleton pattern features:

  • (1) A singleton class can have only one instance
  • (2) A singleton class must create its own unique instance
  • (3) The singleton class must provide this instance to all other objects

Lazy: Instantiate yourself the first time you call it.

  public class Singleton{
    private Singleton(a){}
    private static Singleton single = null;
    Static factory method
    private static Singleton getInstance(a){
      if(single == null) single = new Singleton();
    }
    return single;
  }
Copy the code

Slacker does not consider thread-safety, so it is thread-unsafe. Multiple Singleton instances are likely to occur concurrently. There are three ways to achieve thread-safety:

Add a synchronization keyword to the getInstance method: In a concurrent environment, multiple Singleton instantiation objects are created because the Singleton pattern has not been instantiated and single is null, destroying the desired result of the Singleton pattern. We can add a synchronized lock to the getInstance method.

 public static synchronized Singleton getInstance(a){
   if(single == null) single = new Singleton();
   return single;
 }
Copy the code

Double checklock:

 public static Singleton getInstance(a){
  if(singleton == null){
    synchronized (Singleton.class){
       if(singleton == null) singleton = newSingleton(); }}return singleton;
 }
Copy the code

Singletons for double checklock still need to add volatile to ensure thread safety.

Statically synchronized classes: Achieve thread safety and avoid the performance impact of synchronization.

 public class Singleton{
   private static class LazyHolder{
     private static final Singleton INSTANCE = new Singleton();
   }
   private Singleton(a){}
   public static final Singleton getInstance(a){
     returnLazyHolder.INSTANCE; }}Copy the code

Hungry: Hungry creates a static object for the system to use at the same time the class is created, so it is inherently thread-safe.

  public class Singleton1{
    private Singleton1(a){}
    private static final Singleton1 single = new Singleton1();
    Static factory method
    public static Singleton1 getInstance(a){
       returnsingle; }}Copy the code

Once the class is loaded, the singleton initialization is complete, so that when getInstance is loaded, the singleton already exists. Lazy people are lazy and only initialize getInstance when the user calls it.

conclusion

Life is more than resolute fish struggle, have a dream is meaningful pursuit

Finally, I wish you all to learn as soon as possible, get a satisfactory offer, fast promotion and salary increase, on the peak of life.

Java development communication jun example: 756584822