Java multi-thread

The introduction

What is a process, a thread?

Process:

The smallest unit of resource allocation. The CPU reads a program from disk into memory. The instance of the executing program is called a process. If a program is read into memory by the CPU more than once, it becomes multiple independent processes.

Thread:

Threads are the smallest unit of program execution, and there can be multiple different threads in a process.

Thread application examples:

Better parallel processing within the same application.

Example: How many threads does it take to hand write a text editor?

Why multithreading?

The use of multithreaded code execution, the purpose is to improve the efficiency of program development.

The difference between serial and parallel

The CPU is divided into time slices for alternate execution, macro parallel, micro serial, and the OS is responsible for scheduling. Today’s cpus have evolved to multi-core cpus with true parallelism.

CPU scheduling algorithm

Does multithreading necessarily improve efficiency? Not necessarily. You need to know the CPU scheduling algorithm.

CPU scheduling algorithm:

In a production environment, if we have a lot of threads open but our server has a low number of cores, we will do context switching on the CPU, which will reduce efficiency.

It would be good to use a thread pool to limit the number of threads to the same number of cpus.Copy the code

First, Java multithreading foundation

How a thread is created

  1. inheritanceThreadClass creation thread
  2. implementationRunnableInterface creation thread
  3. Create threads using anonymous inner class form
  4. useLambdaExpression creation
  5. useCallableandFutureCreate a thread
  6. Created using a thread pool
  7. In the Spring@Asynccreate

Here are some examples:

1. The inheritanceThreadClass creation thread

public class ThreadTest extends Thread{
    @Override
    public void run(a) {
        for (int i = 0; i < 10; i++) {
            System.out.println("Child thread, thread one."); }}/* Create the object into its initial state and call start() to enter the ready state. Calling the run() method directly is equivalent to executing run in main. It's not a new thread */
    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        
        // Call the start method here to start the threadt.start(); }}Copy the code
2. ImplementRunnableInterface creation thread
public class ThreadTest02 {
    public static void main(String[] args) {
// Create a thread object
        Thread t = new Thread(new Thread01());

// Start the threadt.start(); }}class Thread01 implements  Runnable{
    /** * the parent interface Runnable run method */
    @Override
    public void run(a) {
// Get the current thread name
        System.out.println(Thread.currentThread().getName() + "I'm a branch thread."); }}Copy the code
3. Create threads using anonymous inner class form
public class ThreadTest03 {
    public static void main(String[] args) {
// Anonymous objects are used to implement the Rnnable interface
        Thread t  = new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println(Thread.currentThread().getName() +"I'm a branch interface"); }}); t.start(); }}Copy the code
Use 4.LambdaExpression creation
public class Thread02  {
    public static void main(String[] args) {
        new Thread(() -> System.out.println(Thread.currentThread().getName()+"I'm a child thread.")).start(); }}Copy the code
5. UseCallableandFutureCreate a thread
Disadvantages of Runnable:1.Run has no return value2.The Callable interface allows threads to have a return value, and the Future interface allows threads to throw an exception to accept the return valueCopy the code
public class Thread03 implements Callable<Integer> {
    /** * The code that the current thread needs to execute, returns the result *@return 1
     * @throws Exception
     */
    @Override
    public Integer call(a) throws Exception {
        System.out.println(Thread.currentThread().getName()+"Returns 1");
        return 1; }}Copy the code
public static void main(String[] args) throws ExecutionException, InterruptedException {
    Thread03 callable = new Thread03();
    FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(callable);
    new Thread(integerFutureTask).start();
    The main thread needs to wait for the child thread to return the result
    Integer result = integerFutureTask.get();
    System.out.println(Thread.currentThread().getName()+","+result); // main,1
}
Copy the code
6. Create using a thread pool
public class ThreadExecutor {
    public static void main(String[] args) {
     ExecutorService executorService = Executors.newCachedThreadPool();
     executorService.execute(new Runnable() {
         @Override
         public void run(a) {
             System.out.println(Thread.currentThread().getName()+"I'm child thread 1."); }}); executorService.submit(new Thread03()); Submit a thread to the thread pool}}Copy the code
7. In the Spring@Asynccreate

Step 1: Enable asynchronous annotations in the entry class

@SpringBootApplication
@EnableAsync
Copy the code

Step 2: Add @async to the current method

@Component
@Slf4j
public class Thread01 {
    @Async
    public void asyncLog(a){
        try {
            Thread.sleep(3000);
            log.info("< 2 >");
        } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

Step 3: Verify the test


@RestController
@Slf4j
public class Service {
    @Autowired
    private Thread01 thread01;
    @RequestMapping("test")
    public String Test(a){
        log.info("< 1 >");
        thread01.asyncLog();
        log.info("< 3 >");
        return "test"; }}Copy the code

Localhost :8080/test


ThreadThe common methods used in

1.The thread.currentthread () method retrieves the currentThread

Any piece of code in Java is executed in a thread, and the thread executing the current code is the current thread.

2.setName()/getName
Thread.setname (thread name)// Set the thread name
thread.getName() // Returns the thread name
Copy the code

Setting a thread name helps debug programs and improves the readability of programs. You are advised to set a name for each thread that reflects the functions of the thread.

3.isAlive()
thread.isAlive() // Check whether the current thread is active
Copy the code
4.sleep()
Thread.sleep(millis); // Sleep the current thread for the specified number of milliseconds
Copy the code

Example: Timer (one minute countdown)

/ * * *@authorFull * createDate 2022/2/2813:21 * Static void sleep (long millis) * 1. Static method: thread.sleep (1000 * 5); * 2. The parameter is millisecond * 3. * If this line of code appears in thread A, thread A will go to sleep. * if this line of code appears in thread B, thread B will go to sleeppublic class ThreadTest05 {
    public static void main(String[] args) {
        // Put the current thread to sleep for 5 seconds
// The current thread is the main thread

        /** try { * Thread.sleep(1000 * 5); * } catch (InterruptedException e) { * e.printStackTrace(); * } * System.out.println("hell0,world"); * /


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

            try {
                Thread.sleep( 1000 * 1);
            } catch(InterruptedException e) { e.printStackTrace(); }}}}Copy the code
5.getId()Threads in Java have a unique number
6.yield()Discard current CPU resources
Thread.yield();  // The thread can be changed from running to ready
Copy the code
7.setPriority()Set the priority of the thread
thread.setPriority(num); To set the priority of a thread, the value is1-10, will throw an exception IllegalArugumentExption if the range is exceeded; A thread with a higher priority has a higher probability of obtaining CPU resources. Priority is essentially just a reminder to the thread scheduler to decide which threads to dispatch first. There is no guarantee that higher-priority lines will run first. Improper Java priority Settings can cause some threads to never run, creating thread hunger. Thread priority is not set as high as possible, and it is not necessary to set thread priority at development time.Copy the code
8.interrupt()Interrupt a Thread (method in Thread).
This is because the interrupt() method only interrupts a thread while it is blocking, not while it is running. Use in a running thread: Note that calling this method simply marks the current thread with a stop flag, not actually stopping the thread. For example, in threads1Interrupt () is called in thread B to handle termination by listening for the interrupt flag in thread B.Copy the code
package se.high.thread;

/ * * *@author gaoziman
 */

public class YieldTest extends Thread {
    @Override
    public void run(a) {
        for (int i = 1; i < 1000; i++) {
            // Determine the interrupt flag
            if (this.isInterrupted()){
                // If true, end the thread
                //break;
                return;
            }
            System.out.println("thread 1 --->"+i); }}}Copy the code
package se.high.thread;

/ * * *@author gaoziman
 */

public class Test {
    public static void main(String[] args) {
        YieldTest t1 = new YieldTest();
        t1.start(); // Start the child thread

        // Current thread main thread
        for (int i = 1; i < 100; i++) {
            System.out.println("main --->" + i);
        }
        // After printing 100 threads in the main thread, interrupt the child thread, which is just a flag that must be processed in the threadt1.interrupt(); }}Copy the code
9.setDaemon()Daemon thread
// before the thread starts
thread.setDaemon(true);
thread.start();
Copy the code

Threads in Java are divided into user threads and daemon threads

Daemon threads are threads that provide services to other threads, such as garbage collection (GC) is a typical daemon thread.

Daemon threads cannot run alone. When there are no other user threads in the JVM, only daemon threads are destroyed and the JVM exits automatically.


Thread state (lifetime of thread)

** Thread state: ** getState()


Second, thread safety principles

Benefits of multithreading:

  1. Improve the systemthroughputMultithreaded programming can make a process haveMultiple concurrent operations.
  2. To improveresponsiveness, the server will use some special threads to handle the user’s request, shortening the user’s waiting time.
  3. Take full advantage of multi-core processor resources, through multi-threading can make full use of CPU resources.

Multithreading problems:

Thread safety issues. Data consistency issues such as reading dirty data (expired data), such as lost data updates, can occur when multiple threads share data without proper concurrent access control measures.

Thread liveness issues. Threads that remain in a non-runnable state due to defects in the program itself or due to resource scarcity are thread activity problems.

Common thread activity issues:

The prince died in the sleeping Beauty story. LiveLock is like a cat that keeps biting its own tail but can’t get it. Starvation is similar to how robust young birds often snatch food from their mothers’ mouths.

Context Switch The processor switches from executing one thread to executing another.

Reliability can be caused by one thread causing the JVM to terminate unexpectedly and other threads to fail to execute. Thread safety

What are thread safety issues?

When multiple threads write (modify) to the instance variable of the same object, they may be interfered by other threads, resulting in thread-safety problems.

Atomic:

Indivisible. When a shared variable is accessed (read, written), the operation has either completed or not yet occurred from the perspective of other threads. The intermediate result of the current operation is invisible to other threads. Atomic operations that access the same set of shared variables cannot be interlaced, such as real-life ATM withdrawals.

There are two ways to achieve atomicity in Java:1.Locks: Locks are exclusive and ensure that shared variables can only be accessed by one thread at a time.2.CAS instruction: implemented directly at the hardware level, as a hardware lock.Copy the code
Visbility:

In a multithreaded environment, when one thread updates a shared variable, subsequent threads may not immediately be able to read the results of the update.

If a thread updates a shared variable, subsequent threads that access the variable can read the result of the update. The update is said to be visible to other threads. Otherwise, updates made by this thread to a shared variable are said to be invisible to other threads.

Multithreaded programs can cause other threads to read old data (dirty data) because of visibility problems.

Ordering:

Memory access operations performed by one thread running on one processor are Out of Order in the view of other threads running on another processor.

Out of order: When the order of memory access operations appears to change.

The JVM with JMM

JVM runtime data area

Let’s talk about the runtime data area first. The following diagram is familiar to all of you:

For each thread, the stack is private and the heap is common.

This means that variables on the stack (local variables, method definition parameters, exception handler parameters) are not shared between threads, and there are no memory visibility issues (described below), nor are they affected by the memory model. Variables in the heap are shared and are referred to in this article as shared variables.

So, memory visibility is for shared variables.

Examples of thread insecurity arise

public class ThreadCount implements Runnable{
    private int count =100;

    @Override
    public void run(a) {
        while(true) {if (count>0){
                count--;
                System.out.println(Thread.currentThread().getName()+"-- -- -- -- >"+count); }}}public static void main(String[] args) {
        ThreadCount threadCount = new ThreadCount();
        new Thread(threadCount).start();
        newThread(threadCount).start(); }}Copy the code

How to solve the thread safety problem?

Core idea: lock

In the same JVM, multiple threads need to lock the resource competition, finally can only have a thread to get the lock, multiple threads at the same time take a lock, which thread will be able to get to the lock, and who can perform this code, without acquiring a lock is successful, the need to experience the lock in the middle of the upgrade process, if there has been no get it has been blocked waiting for the lock.

For example, how to lock in the above case?

public class ThreadCount implements Runnable{
    private  int count =100;

    @Override
    public void run(a) {
        while(true) {synchronized (this) {if (count>0) {/* Thread 0 thread 1 acquires this lock at the same time, assuming thread 0 acquires this lock, meaning thread 1 does not acquire this lock and will wait. After thread 0 completes count-- releasing the lock resource, thread 1 is awakened to re-enter the resource that acquired the lock. All locks are obtained and released by virtual machines */
               
                    count--;
                    System.out.println(Thread.currentThread().getName()+"--"+count); }}}}public static void main(String[] args) {
        ThreadCount threadCount = new ThreadCount();
        new Thread(threadCount).start();
        newThread(threadCount).start(); }}Copy the code

Third, thread synchronization

Thread synchronization can be understood as executing in a certain order between threads.

There is a concept of synchronization between our threads. What is synchronization, if we have it now2Thread A and thread B. While they were copying, the teacher suddenly came and changed some of the answers. Maybe A and B ended up writing different summer homework. We can write this for A and B2This same summer homework, we need to let the teacher first modify the answer, and then A, B students copy. Or A, B students first copy, the teacher can modify the answer. This is thread synchronization for thread A and thread B.Copy the code

Thread safety is generated because there is no synchronization between multiple threads. Thread synchronization mechanism is a set of data access mechanism used to coordinate threads, which can ensure thread safety.

The Java platform provides threading mechanisms that include locking, volatile, final, static, and related apis, objet.wait (); Object. Notify (), etc.

The concept of the lock

The premise of thread safety is that multiple threads concurrently access shared data, and the concurrent access of multiple threads to shared data is converted into serial access, that is, one shared data can only be accessed by one thread at a time. Locks are thread-safe in this way.

The JVM divides locks into internal and display locks. Internal passagesynchronizedKeyword realization; Show lock passjava.concurrent.locks.lockInterface implementation class implementation.

Functions of ** locks: ** locks can achieve secure access to shared data, ensuring atomicity, visibility, and order of threads.

  • Locking is atomicity guaranteed by mutual exclusion. A lock can only be held by one thread. This ensures that critical section code can only be executed by one thread at a time, making operations indivisible and atomicity guaranteed.
  • Visibility is guaranteed through the actions of the writer thread flushing the processor cache and the reader thread flushing the processing cache. In Java. The acquisition of the lock implies the flushing of the processor cache, and the release of the lock implies the flushing of the processor cache. To ensure that the data changes made by the writer thread are first pushed to the cache of the refresh processor to ensure that the reader thread is first visible.
  • Locking ensures order, and the writer thread performs critical sections that appear to be executed in source order.

Note: Using locks to secure threads must meet the following conditions:

  • These threads must use the same lock when accessing shared data.
  • These threads need to use locks even if they are just reading shared data.

Internal lock: synchronized

Each object in Java has an internal lock associated with it (also known as a Monitor Monitor), which is an exclusive lock that guarantees atomicity, visibility, and order.

A critical area is an area of code that can only be executed by one thread at a time. If the synchronized keyword is in a method, the critical section is the entire method interior. With synchronized blocks, a critical section is the area inside the block.

Synchronized is used in several scenarios:

1. Synchronized modifies a code block, called a synchronized statement block, which acts on the code enclosed in braces {} and on the object calling the block;

synchronized(object) {synchronized code block, can access Shared data in synchronized code block} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --package se.high.thread.intrinsiclock;

/ * * *@authorGaoziman * Synchronize code block */

public class Test01 {
    public static void main(String[] args) {
        // Create two threads calling the mm() method
        // Create Test01 and call mm() with the object name
        Test01 obj = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                obj.mm(); // Use the lock object this is the obj object
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run(a) {
                obj.mm(); // Use the lock object this is the obj object
            }
        }).start();

    }

    // Define a method that prints a string of 100 lines
    public void mm(a){
        // Use this as the lock object
        synchronized (this) {for (int i = 0; i <100; i++) {
            System.out.println(Thread.currentThread().getName()+"-- -- -- -- >"+i); }}}}Copy the code

2. Synchronized modifies a method. The modified method is called a synchronized method.

package se.high.thread.intrinsiclock;

/ * * *@authorWang Ze * synchronization instance method, the whole method body as synchronization code block. * The default lock object is this. * /

public class Test02 {
    public static void main(String[] args) {
        // Create two threads, calling mm() method mm2 respectively
        Test02 obj = new Test02();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                obj.mm(); // Use the lock object this is the obj object
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                obj.mm2(); // Use the lock object this is the obj object
            }
        }).start();

    }
    public void mm(a){
        // Use this as the lock object
        synchronized (this) {for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+"-- -- -- -- >"+i); }}}/** * synchronizes instance methods, with this as the default lock object. * /
    public synchronized void mm2(a){
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"- >"+i); }}}Copy the code

3. Synchronized refers to a static method whose scope is the entire static method and its objects are all objects of the class;

On static methods, lock to the current Class object
public static synchronized void classLock(a) {
    // code
}
Copy the code

Equivalent to the = = =

// The keyword is in the code block, locked as the object inside the parentheses
public void blockLock(a) {
    synchronized (this.getClass()) {
        // code}}Copy the code

4. Synchronized modifies a class that applies to all objects of the class enclosed in parentheses after synchronized.

Conclusion:

Synchronizing code blocks is more efficient than synchronizing methods. Dirty reads occur because the modification of the shared data is not synchronized with the reading of the shared data. The block of code that reads data needs to be synchronized. The lock is automatically released when the thread is abnormal.

Seven cases of multithreaded access to synchronous methods

A synchronous method in which two threads simultaneously access an object

A: Serial execution

2. Two threads access synchronized methods of two objects

A: Parallel execution, because the two threads hold their own object locks and complement each other.

3. Both threads access static methods of synchronized

A: Execute serially, holding a class lock

4. Access both synchronous and asynchronous methods

A: Parallel execution, whether the same object or different objects, ordinary methods are not affected

Different common synchronization methods for accessing the same object

A: Execute serially, holding the same lock object

6. Access both static and non-static synchronized methods

A: Parallel execution, because one holds the class lock and one holds the this lock, different locks, complementary interference.

When the method throws an exception, the lock is released

A: Synchronized releases the lock whether it is normal or after an exception is thrown. Lock must be released manually.

Deadlock issues

A deadlock is a situation in which multiple threads are blocked at the same time, and one or all of them are waiting for a resource to be released. Because the thread is blocked indefinitely, the program cannot terminate normally.

There are four necessary conditions for Java deadlocks to occur:

(1) Mutually exclusive use, that is, when a resource is used (occupied) by one thread, other threads cannot use it. (2) Non-preemption, the resource requester cannot forcibly seize resources from the hands of the resource possessor, resources can only be released by the initiative of the resource possessor. 3. Request and hold, that is, when the resource requester requests other resources while maintaining the possession of the original resource. 4. Cyclic waiting, that is, there is a waiting queue: P1 occupies P2 resources, P2 occupies P3 resources, and P3 occupies P1 resources. This creates a waiting loop.

When all four conditions are true, a deadlock occurs. Of course, if any of these conditions are broken in a deadlock case, the deadlock will disappear. The following uses Java code to simulate deadlock generation:

package se.high.thread.intrinsiclock;

import javax.security.auth.Subject;

/ * * *@authorGaoziman * shows deadlock problem. * In multithreaded programs, multiple locks may be required for synchronization, which may result in deadlocks if the locks are obtained in an inconsistent order. * /

public class DeadLock {
    public static void main(String[] args) {
        SubThread t1 =new SubThread();
        t1.setName("a");
        t1.start();

        SubThread t2 = new SubThread();
        t2.setName("b");
        t2.start();

    }

    static class SubThread extends Thread{
        private static final Object yitian = new Object();
        private static final Object tulong = new Object();
        @Override
        public void run(a) {
            if ("a".equals(Thread.currentThread().getName())){
                synchronized (yitian){
                    System.out.println("A thread got the heavenly sword, turned over, and then a dragon sword...");
                    synchronized (tulong){
                        System.out.println("A thread obtained the heavenly Sword and dragon sword, directly dominate the wulin..."); }}}if ("b".equals(Thread.currentThread().getName())){
                synchronized (tulong){
                    System.out.println("B thread got dragon sword, well, who also don't give....");
                    synchronized (yitian){
                        System.out.println("B thread to get the dragon after the sword.... B: Master wulin");
                    }
                }
            }
        }
    }
}
Copy the code

Resolve deadlocks:

When multiple locks need to be acquired, all threads acquire the locks in the same order.


4. Communication between threads

It is well known that threads have their own thread stack, so how do threads ensure communication? Here’s the analysis:

Wait/notification mechanism

What is the wait notification mechanism?

Example: eat buffet to eat some of the food, put on the table to take.

In single-threaded programming, the action to be performed is conditional and can be placed in an if block.

In multithreaded programming, it may only be temporary that thread A’s condition is not met. Later, another thread B may update the condition so that thread A’s condition is met. Thread A can be suspended until its condition is met and then woken up.

Pseudo code:

atomic{
    while(Condition not true) {wait} After the condition is met, the current thread wakes up and continues to perform the following operation}Copy the code

Waiting for notification mechanism implementation:

The wait() method in the Object class causes the thread currently executing code to wait. Suspend execution until received until notified or interrupted.

Note:

  1. The wait() method can only be called by a lock object in a synchronized block of code.
  2. After calling wait(), the current thread releases the lock.

Pseudo code:

Obtain the internal lock of the object before calling wait()
synchronized(Lock object){while(Condition not true){// Call wait() to suspend the thread and release the lock objectLock object. Wait (); }// The thread condition is satisfied to continue execution
}
Copy the code

The notify() method of the Object class wakes up threads, which must also be called by the lock Object in the synchronized code block. Calling wait()/notify() without a lock object throws an exception.

If there are multiple waiting threads, the **notify() method only wakes up one of them and does not immediately release the lock object. ** The notify method is usually placed at the end of the synchronized code block.

Pseudo code:

synchronized(lock object){execute code that changes the protection condition to wake up another thread lock object. Notify (); }Copy the code

Here’s an example:

package se.high.thread.wait;

/ * * *@authorStructured thinking WZ * wakes up a waiting thread with notify */

public class Test01 {

    public static void main(String[] args) {
        String lock = "wzjiayou"; // Define a string as a lock object
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run(a) {
                synchronized (lock){
                    System.out.println("Thread 1 starts waiting -->"+System.currentTimeMillis());
                    try {
                        lock.wait(); // The thread waits
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Thread 1 finishes waiting -->"+System.currentTimeMillis()); }}});/** * defines thread 2 to wake up thread 1 */
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run(a) {
                // Notify needs to be called by the lock object in the synchronized code block
                synchronized (lock){
                    System.out.println("Thread 2 is waking up"+System.currentTimeMillis());
                    lock.notify();
                    System.out.println("Thread 2 ends wake up"+System.currentTimeMillis()); }}}); t1.start();// Start t1 thread,main thread who 3 seconds, make sure T1 waits
        try {
            Thread.sleep(3000);
        } catch(InterruptedException e) { e.printStackTrace(); } t2.start(); }}Copy the code

Execution Result:

thread1Start waiting -->1633345984896thread2Began to wake up1633345987897thread2End of wake up1633345987897thread1End the wait -->1633345987897The process has ended and the exit code is0
Copy the code

The interrupt() method interrupts wait()

When a thread is in wait() state, calling interrupt() on a thread object interrupts the wait state, raising InterruptedExceptiont.

Notify () and notifyAll ()

Notify () can only wake up one thread at a time. If there are multiple waiting threads, only one of them can be woken up randomly. To wake up all threads, call notifyAll();

wait(long)

If the alarm is not woken up within the specified time, the alarm is automatically woken up after the timeout.

Notice too early

If notify() is called too early, calling notify() before waiting may disrupt the program’s normal execution logic.

In our application, we make sure t1 waits before t2 wakes up. If t2 wakes up first, t1 is not allowed to wait.

You can set a Boolean variable to false after notification and wait if true.

The wait() condition has changed

When using wait(),notify(), notice that the wait condition changes, which can also cause logic confusion.

* Producer-consumer model

The producer-consumer problem, also known as the Bounded buffer problem, is a classic case of multi-thread synchronization. The producer generates a certain amount of data and puts it in the buffer, and then repeats the process. At the same time, consumers consume this data in the buffer. There must be synchronization between producers and consumers to ensure that producers do not put data in when the buffer is full and consumers do not consume data when the buffer is empty. Imperfect solutions are prone to deadlock situations where processes are waiting to wake up.

Schematic diagram:

Solution:

  1. Adopt some mechanism to protect synchronization between producers and consumers. High efficiency, and easy to implement, the code can control better, belongs to the common mode.

  2. Build a pipeline between producers and consumers. Pipeline buffer is not easy to control, and the transmitted data object is not easy to encapsulate, so it is not practical.

Solve the core of the problem:

Ensures integrity when the same resource is accessed concurrently by multiple threads. The common synchronization method is to use a signal or locking mechanism to ensure that the resource can be accessed by at most one thread at any time.

Wait ()/notify() methods

When the buffer is full, the producer thread stops executing, gives up the lock, puts itself in a wait state, and lets other threads execute.

When the buffer is empty, the consumer thread stops execution, waives the lock, and leaves itself in a wait state for another thread to execute.

When a producer puts a product into the buffer, it sends an executable notification to other waiting threads and waives the lock, leaving itself in a waiting state. When a consumer pulls a product out of the buffer, it sends an executable notification to other waiting threads and waives the lock, leaving itself in the wait state.

Warehouse Storage. Java

import java.util.LinkedList;

public class Storage {
// Storage capacity
private final int MAX_SIZE = 10;
// Warehouse storage carrier
private LinkedList<Object> list = new LinkedList<>();

public void produce(a) {
    synchronized (list) {
        /* The warehouse is full */
        while (list.size() + 1 > MAX_SIZE) {
            System.out.println("[Producer]" + Thread.currentThread().getName()
	                + ": The warehouse is full");
            try {
                list.wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}/* The producer produces */
        list.add(new Object());
        System.out.println("[Producer]" + Thread.currentThread().getName()
                + "] Produce a product, now in stock"+ list.size()); list.notifyAll(); }}public void consume(a) {
    synchronized (list) {
        /* The warehouse is empty */
        while (list.size() == 0) {
            System.out.println("[Consumer]" + Thread.currentThread().getName() 
					+ "The warehouse is empty");
            try {
                list.wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}/* Consumer spending */
        list.remove();
        System.out.println("[Consumer]" + Thread.currentThread().getName()
                + "] Consume a product, now in stock"+ list.size()); list.notifyAll(); }}}Copy the code

Producers:

public class Producer implements Runnable{
private Storage storage;
public Producer(a){}
public Producer(Storage storage){
    this.storage = storage;
}

@Override
public void run(a){
    while(true) {try{
            Thread.sleep(1000);
            storage.produce();
        }catch(InterruptedException e){ e.printStackTrace(); }}}}Copy the code

consumers

public class Consumer implements Runnable{
private Storage storage;
public Consumer(a){}

public Consumer(Storage storage){
    this.storage = storage;
}

@Override
public void run(a){
    while(true) {try{
            Thread.sleep(3000);
            storage.consume();
        }catch(InterruptedException e){ e.printStackTrace(); }}}}Copy the code

Main:

public class Main {
public static void main(String[] args) {
    Storage storage = new Storage();
    Thread p1 = new Thread(new Producer(storage));
    Thread p2 = new Thread(new Producer(storage));
    Thread p3 = new Thread(new Producer(storage));

    Thread c1 = new Thread(new Consumer(storage));
    Thread c2 = new Thread(new Consumer(storage));
    Thread c3 = new Thread(new Consumer(storage));

    p1.start();
    p2.start();
    p3.start();
    c1.start();
    c2.start();
    c3.start();
}}
Copy the code
Operation result [producer P1] produces a product, now in stock1[Producer P2] Produces a product, now in stock2[Producer P3] Produces a product, now in stock3[Producer P1] produces a product, now in stock4[Producer P2] Produces a product, now in stock5[Producer P3] Produces a product, now in stock6[Producer P1] produces a product, now in stock7[Producer P2] Produces a product, now in stock8[Consumer C1] Consumes a product, now in stock7[Producer P3] Produces a product, now in stock8[Consumer C2] Consume a product, now in stock7[Consumer C3] Consume a product, now in stock6[Producer P1] produces a product, now in stock7[Producer P2] Produces a product, now in stock8[Producer P3] Produces a product, now in stock9[Producer P1] produces a product, now in stock10[Producer P2] warehouse is full [Producer P3] Warehouse is full [Producer P1] Warehouse is full [Consumer C1] Consumed a product, now in stock9[Producer P1] produces a product, now in stock10[Producer P3] Warehouse is full... The following is omittedCopy the code

A producer thread runs the Produce method, sleep 1s; A consumer runs the consume method once, sleeping 3s. In this case, we have 3 producers and 3 consumers, which is what we call a many-to-many situation. The warehouse capacity is 10, it can be seen that the speed of consumption is obviously slower than the speed of production, in line with the setting.

Note:

NotifyAll () causes all “all” threads in the wait queue waiting for the same shared resource to exit from the wait state and enter the runnable state. At this point, the highest priority thread executes first, but it can also execute randomly, depending on the IMPLEMENTATION of the JVM virtual machine. In the end, only one thread can be run. The priority of each thread is the same, and the priority of each thread is not determined. Later, the priority of the thread is set differently than expected, depending on the implementation of the JVM.

join()

The Join () method is an instance of the Thread class. It is used to keep the current thread in a “wait” state until the join thread completes.

Sometimes, the main thread creates and starts a child thread, and if a lot of time-consuming computation is required in the child thread, the main thread will often end before the child thread ends.

The join method is used if the main thread wants to wait for the child thread to finish executing and then retrieve some data that has been processed in the child thread. (in)

public class Join {
    static class ThreadA implements Runnable {

        @Override
        public void run(a) {
            try {
                System.out.println("I'm a child thread. I'll sleep for a second.");
                Thread.sleep(1000);
                System.out.println("I'm a child thread. I'm done for a second.");
            } catch(InterruptedException e) { e.printStackTrace(); }}}public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadA());
        thread.start();
        thread.join();
        System.out.println("If I don't add the join method, I will be typed out first. If I add the join method, it will be different."); }}Copy the code

Note that the join() method has two overloaded methods: join(long) and join(long, int).

In fact, as you can see from the source code, both the join() method and its overloading methods make use of wait(long) at the bottom.

For join(long, int), a look at the source code (JDK 1.8) shows that the bottom layer is not accurate to nanosecond, but does a simple judgment and processing on the second parameter.

5. Callable and Future

In general, we use Runnable and Thread to create a new Thread. But they have one drawback: the run method returns no value. Sometimes we want to start a thread to perform a task and return a value when the task completes.

The JDK provides Callable and Future interfaces to solve this problem, which is also called the “asynchronous” model.

Callable interface

Callable, like Runnable, is a functional interface that has only one abstract method. The difference is that Callable provides methods that return values and support generics.

@FunctionalInterface
public interface Callable<V> {
    V call(a) throws Exception;
}
Copy the code

How do you use Callable in general? Callable is typically used in conjunction with the thread pool tool ExecutorService. We will explain the use of thread pools in a later section. The ExecutorService can use the Submit method to execute a Callable interface. It’s going to return a Future, and our Future programs can get results from that Future’s get method.

Here’s a simple demo:

// Customize Callable
class Task implements Callable<Integer>{
    @Override
    public Integer call(a) throws Exception {
        // Simulation takes one second
        Thread.sleep(1000);
        return 2;
    }
    public static void main(String args[]) throws Exception {
        / / use
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> result = executor.submit(task);
        // Note that calling the get method blocks the current thread until the result is obtained.
        // Therefore, it is recommended to use overloaded GET methods that can set timeout.System.out.println(result.get()); }}Copy the code

Output result:

2
Copy the code
The Future interface

There are only a few simple methods for the Future interface:

public abstract interface Future<V> {
    public abstract boolean cancel(boolean paramBoolean);
    public abstract boolean isCancelled(a);
    public abstract boolean isDone(a);
    public abstract V get(a) throws InterruptedException, ExecutionException;
    public abstract V get(long paramLong, TimeUnit paramTimeUnit)
            throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code

The cancel method attempts to cancel execution of a thread.

Note that an attempt to cancel may not be successful. Because the task may have been completed, cancelled, or some other factor cannot be cancelled, there is a possibility that cancellation will fail. The Boolean type returns a value that means “cancelled successfully or not.” The paramBoolean parameter indicates whether to abort the thread execution.

So sometimes a Callable is used instead of a Runnable in order to make a task unusable. If a Future is used for cancelability but no results are available, you can declare a Future<? >, and returns NULL as the result of the underlying task.

FutureTask class

The Future interface was introduced above. This interface has an implementation class called FutureTask. FutureTask implements the RunnableFuture interface, which inherits both the Runnable and Future interfaces:

public interface RunnableFuture<V> extends Runnable.Future<V> {
    /** * Sets this Future to the result of its computation * unless it has been cancelled. */
    void run(a);
}
Copy the code

So what’s the FutureTask class for? Why have a FutureTask class? The Future is just an interface, and its cancel, GET, isDone and other methods are very complicated to implement by themselves. So the JDK provides a FutureTask class for us to use.

Example code:

// Custom Callable, as above
class Task implements Callable<Integer>{
    @Override
    public Integer call(a) throws Exception {
        // Simulation takes one second
        Thread.sleep(1000);
        return 2;
    }
    public static void main(String args[]) throws Exception {
        / / use
        ExecutorService executor = Executors.newCachedThreadPool();
        FutureTask<Integer> futureTask = new FutureTask<>(newTask()); executor.submit(futureTask); System.out.println(futureTask.get()); }}Copy the code

There is a slight difference in usage from the first Demo. First, calling the Submit method returns no value. In this case, the submit(Runnable Task) method is actually called, whereas in the Demo above, the Submit (Callable Task) method is called.

Then, FutureTask is used to fetch the get value directly, whereas the Demo above uses the Future returned by the Submit method to fetch the value.

In many high-concurrency environments, it is possible for Callable and FutureTask to be created multiple times. FutureTask can ensure that tasks are executed only once in high-concurrency environments.


reflection

I. Overview of reflection

The Java reflection mechanism is a real running state in which the properties and methods of any class can be known. For any object, you can call any of its methods and properties; This ability to dynamically retrieve information and invoke methods on objects is called Java reflection.

To parse a class, you must get the bytecode file object for that class. Parsing uses Class methods, so you need to get an object of Class type corresponding to the bytecode file.

So what is reflection

Reflection is the mapping of various components of a Java class to Individual Java objects

For example: a class has: member variables, methods, constructors, packages and other information, the use of reflection technology can be dissected on a class, the mapping of each component into one object.

This is the normal loading process of a class: reflection works in the same way as the class object. Familiarize yourself with loading time: Class objects are created by reading a Class file into memory and creating a Class object for it.

This Class object is special. Let’s take a look at the C lass class


Class API in Java

Instances of the Class Class represent classes and interfaces in a running Java application. That is, there are N more instances in the JVM and each Class has that Class object. (Including basic data types)

Class has no public constructor. Class objects are automatically constructed by the Java Virtual machine when the Class is loaded and by calling the defineClass method in the Class loader. That is, we don’t need to handle the creation ourselves, the JVM already does it for us.

There are no common constructors; 64 methods are too many. We only need to know some common ones

Three, the use of reflection

Here’s an example:

So let’s do a Student class.

There are three ways to get a Class object

  1. Object – > getClass ();
  2. Any data type, including basic data types, has a “static” class attribute
  3. Static method through Class: forName (String className) (common)

The 1.1 is because of the getClass method in the Object class, and because all classes inherit from the Object class. Call the Object class to get it

package fanshe;
* 1 Object -- > getClass(); * 2 Any data type (including basic data types) has a "static" class attribute * 3 Through the static method of the class class: forName (String className) (common) */
public class Fanshe {
	public static void main(String[] args) {
		// The first way to get a Class object
		Student stu1 = new Student();// This new generates a Student object and a Class object.
		Class stuClass = stu1.getClass();// Get the Class object
		System.out.println(stuClass.getName());
		
		// The second way to get a Class object
		Class stuClass2 = Student.class;
		System.out.println(stuClass == stuClass2);// Check whether the Class object obtained in the first way is the same as the Class object obtained in the second way
		
		// The third way to get a Class object
		try {
			Class stuClass3 = Class.forName("fanshe.Student");// Note that this string must be the real path, i.e. the classpath with the package name, package name. The name of the class
			System.out.println(stuClass3 == stuClass2);// Check whether the three methods get the same Class object
		} catch(ClassNotFoundException e) { e.printStackTrace(); }}}Copy the code

Note: At runtime, only one Class object is generated for each Class.

There are three ways to use the third way, the first object has to reflect what. The second need to import class package, too strong dependence, do not guide package to throw compiler errors. Generally the third way, a string can be passed in or written to a configuration file.

Get the constructor from reflection and use:

Student class:

package fanshe;
 
public class Student {
	
	//--------------- constructor -------------------
	// (default constructor)
	Student(String str){
		System.out.println("(default) constructor s =" + str);
	}
	
	// no argument constructor
	public Student(a){
		System.out.println("The public, no-argument constructor was called to execute...");
	}
	
	// There is a constructor for a parameter
	public Student(char name){
		System.out.println("Name:" + name);
	}
	
	// a constructor with multiple arguments
	public Student(String name ,int age){
		System.out.println("Name:"+name+"Age:"+ age);// There is a problem with the execution efficiency, which will be solved later.
	}
	
	// Protected constructor
	protected Student(boolean n){
		System.out.println("Protected constructor n =" + n);
	}
	
	// Private constructor
	private Student(int age){
		System.out.println("Private constructor age:"+ age); }}Copy the code

There are 6 construction methods;

The test class:

package fanshe;
 
import java.lang.reflect.Constructor;
 
 
/* * The Class object is used to obtain the constructor, member variable, and member method of a Class. And access members; Public Constructor[] getConstructors() : public Constructor[] getConstructors() : Public Constructor[] getDeclaredConstructors() : Get all constructors (private, protected, default, public) * 2). Get a single method and call: * public Constructor getConstructor(Class... ParameterTypes: gets a single "public" Constructor: * public Constructor getDeclaredConstructor(Class... ParameterTypes: gets "a constructor" that can be private, protected, default, or public. Constructor-->newInstance(Object... initargs) */
public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1. Load the Class object
		Class clazz = Class.forName("fanshe.Student");
		
		
		//2. Get all public constructors
		System.out.println("* * * * * * * * * * * * * * * * * * * * * * all public constructor to * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		
		System.out.println("* * * * * * * * * * * * all the constructor (including: private, protected, by default, the public) * * * * * * * * * * * * * * *");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("* * * * * * * * * * * * * * * * * access to the public, no arguments constructor * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
		Constructor con = clazz.getConstructor(null);
		//1> < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; white-space: inherit! Important;
		//2>, returns the class object describing the no-argument constructor.
	
		System.out.println("con = " + con);
		// Call the constructor
		Object obj = con.newInstance();
	//	System.out.println("obj = " + obj);
	//	Student stu = (Student)obj;
		
		System.out.println("* * * * * * * * * * * * * * * * * * access to the private constructor, and call the * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
		con = clazz.getDeclaredConstructor(char.class);
		System.out.println(con);
		// Call the constructor
		con.setAccessible(true);// Violent access (ignore access modifiers)
		obj = con.newInstance('male'); }}Copy the code

Execution Result:

* * * * * * * * * * * * * * * * * * * * * * all public constructor * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
publicFanshe. Student () * * * * * * * * * * * * all the constructor (including: private, protected, by default, the public) * * * * * * * * * * * * * * *private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
publicFanshe. Student () fanshe. Student (Java. Lang. String) * * * * * * * * * * * * * * * * * access to the public, no arguments constructor * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * con =publicFanshe.student () calls the public, no-argument constructor to execute... * * * * * * * * * * * * * * * * * * access to the private constructor, and call the * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *public fanshe.Student(char) Name: MaleCopy the code

Call method:

Public Constructor[] getConstructors() public Constructor[] getDeclaredConstructors() public Constructor[] getDeclaredConstructors() : Get all constructors (private, protected, default, public)

Public Constructor getConstructor(Class… ParameterTypes: Gets a single “public” Constructor: public Constructor getDeclaredConstructor(Class… ParameterTypes: gets “a constructor” that can be private, protected, default, or public.

Call Constructor: Constructor–>newInstance(Object… initargs)

2, newInstance is a Constructor class method (a class that manages the Constructor function). Initargs) uses the Constructor represented by this Constructor object to create a new instance of the Constructor’s declarative class and initialize it with the specified initialization parameters. Its return value is of type T, so newInstance is a newInstance object of the declaration class that creates a constructor. And call it

3. Get the member variable and call

Student class:

package fanshe.field;
 
public class Student {
	public Student(a){}/ / * * * * * * * * * * fields * * * * * * * * * * * * * / /
	public String name;
	protected int age;
	char sex;
	private String phoneNum;
	
	@Override
	public String toString(a) {
		return "Student [name=" + name + ", age=" + age + ", sex=" + sex
				+ ", phoneNum=" + phoneNum + "]"; }}Copy the code

The test class:

package fanshe.field;
import java.lang.reflect.Field;
Field[] getFields(): obtain all public fields * 2).Field[] getDeclaredFields(): obtain all public fields, including: private, protected, default, public; Public Field getField(String fieldName): getField(String fieldName): getField(String fieldName); Public Field getDeclaredField(String fieldName); public Field getDeclaredField(String fieldName); * Field --> public void set(Object obj,Object value): * 2.value: The value to be set for the field; * * /
public class Fields {
 
		public static void main(String[] args) throws Exception {
			//1. Get the Class object
			Class stuClass = Class.forName("fanshe.field.Student");
			//2. Get the field
			System.out.println("************ Get all public fields ********************");
			Field[] fieldArray = stuClass.getFields();
			for(Field f : fieldArray){
				System.out.println(f);
			}
			System.out.println("* * * * * * * * * * * * to get all of the fields (including private, protected, the default) * * * * * * * * * * * * * * * * * * * *");
			fieldArray = stuClass.getDeclaredFields();
			for(Field f : fieldArray){
				System.out.println(f);
			}
			System.out.println("* * * * * * * * * * * * * * * to get public fields and call * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
			Field f = stuClass.getField("name");
			System.out.println(f);
			// Get an object
			Object obj = stuClass.getConstructor().newInstance();// Create Student object -- "Student stu = new Student();
			// Set the value for the field
			f.set(obj, "Andy Lau");// Assign the name attribute to the Student object -- "stu.name =" Andy Lau"
			/ / verification
			Student stu = (Student)obj;
			System.out.println("Verify name:" + stu.name);
			
			
			System.out.println("* * * * * * * * * * * * * * for private fields and call * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
			f = stuClass.getDeclaredField("phoneNum");
			System.out.println(f);
			f.setAccessible(true);// Violent reflection, remove private qualifier
			f.set(obj, "18888889999");
			System.out.println("Verification Phone:"+ stu); }}Copy the code

Execution Result:

************ Obtain all public fields ********************publicJava. Lang. String fanshe. Field. Student. Name * * * * * * * * * * * * to get all of the fields (including private, protected, the default) * * * * * * * * * * * * * * * * * * * *public java.lang.String fanshe.field.Student.name
protected int fanshe.field.Student.age
char fanshe.field.Student.sex
privateJava. Lang. String fanshe. Field. Student. PhoneNum * * * * * * * * * * * * * * * to get public fields and call * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *publicJava. Lang. String fanshe. Field. Student. The name verification name: Andy lau * * * * * * * * * * * * * * for private fields and call * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *privateJava. Lang. String fanshe. Field. Student. PhoneNum verify phone: Student [name = Andy lau, age =0, sex=
Copy the code

To call a field, pass two arguments:

Object obj = stuClass.getConstructor().newInstance(); // Create Student object — “Student stu = new Student(); F.et (obj, “Andy Lau “); // Assign the name attribute in the Student object — “stu.name =” Andy lau

4. Get member methods and call

Student class:

package fanshe.method;
 
public class Student {
	//************** Member method ***************//
	public void show1(String s){
		System.out.println(Show1 (): s = public + s);
	}
	protected void show2(a){
		System.out.println("Called: protected, no-argument show2()");
	}
	void show3(a){
		System.out.println("Called: default, no-argument show3()");
	}
	private String show4(int age){
		System.out.println("Show4 (): age =" called, private, int argument show4(): age =" + age);
		return "abcd"; }}Copy the code

The test class:

package fanshe.method;
 
import java.lang.reflect.Method;
 
* * public Method[] getMethods(): getMethods(); Public Method[] getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(): getDeclaredMethods(); Public Method getMethod(String name,Class
      ... ParameterTypes: * parameter: * name: method name; * Class ... Public Method getDeclaredMethod(String name,Class
      ... ParameterTypes: parameterTypes --> Public Object invoke(Object obj,Object... Args): * obj: the object to call the method; * args: arguments passed when calling methods;) : * /
public class MethodClass {
 
	public static void main(String[] args) throws Exception {
		//1. Get the Class object
		Class stuClass = Class.forName("fanshe.method.Student");
		//2. Get all public methods
		System.out.println("*************** Get all public methods *******************");
		stuClass.getMethods();
		Method[] methodArray = stuClass.getMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		System.out.println("*************** get all methods, including private *******************");
		methodArray = stuClass.getDeclaredMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		System.out.println("* * * * * * * * * * * * * * * to get public show1 () method is * * * * * * * * * * * * * * * * * * *");
		Method m = stuClass.getMethod("show1", String.class);
		System.out.println(m);
		// instantiate a Student object
		Object obj = stuClass.getConstructor().newInstance();
		m.invoke(obj, "Andy Lau");
		
		System.out.println("*************** get private show4() method ******************");
		m = stuClass.getDeclaredMethod("show4".int.class);
		System.out.println(m);
		m.setAccessible(true);// Remove the private qualification
		Object result = m.invoke(obj, 20);// Two arguments are required, one for the object to be called (get reflected) and one for the argument
		System.out.println("Return value:"+ result); }}Copy the code

Execution Result:

*************** Get all "public" methods *******************public void fanshe.method.Student.show1(java.lang.String)
public final void java.lang.Object.wait(long.int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native voidJava.lang.object. NotifyAll () * * * * * * * * * * * * * * * to get all of the methods, including private * * * * * * * * * * * * * * * * * * *public void fanshe.method.Student.show1(java.lang.String)
private java.lang.String fanshe.method.Student.show4(int)
protected void fanshe.method.Student.show2()
voidFanshe. Method. Student. Show3 () * * * * * * * * * * * * * * * to get public show1 () method is * * * * * * * * * * * * * * * * * * *public voidFanshe. Method. Student. Show1 (Java. Lang. String) calls: public, String parameter of show1 () : S = Andy lau * * * * * * * * * * * * * * * to get private show4 () method is * * * * * * * * * * * * * * * * * *private java.lang.String fanshe.method.Student.show4(int) called, private, and has a return value,intArgument show4(): age =20Return value: abcdCopy the code

Thus it can be seen that:

m = stuClass.getDeclaredMethod(“show4”, int.class); // To call a specified method (all private), you need to pass in two parameters, the first is the name of the called method, and the second is the type of the method parameter.

System.out.println(m); m.setAccessible(true); Object result = m.invoke(obj, 20); Println (” return value: “+ result);

Execution Result:

*************** Get all "public" methods *******************public void fanshe.method.Student.show1(java.lang.String)
public final void java.lang.Object.wait(long.int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native voidJava.lang.object. NotifyAll () * * * * * * * * * * * * * * * to get all of the methods, including private * * * * * * * * * * * * * * * * * * *public void fanshe.method.Student.show1(java.lang.String)
private java.lang.String fanshe.method.Student.show4(int)
protected void fanshe.method.Student.show2()
voidFanshe. Method. Student. Show3 () * * * * * * * * * * * * * * * to get public show1 () method is * * * * * * * * * * * * * * * * * * *public voidFanshe. Method. Student. Show1 (Java. Lang. String) calls: public, String parameter of show1 () : S = Andy lau * * * * * * * * * * * * * * * to get private show4 () method is * * * * * * * * * * * * * * * * * *private java.lang.String fanshe.method.Student.show4(int) called, private, and has a return value,intArgument show4(): age =20Return value: abcdCopy the code

Actually, the member methods here: there’s a property in the model, those setter () methods and getter() methods. And the composition of the fields, which are detailed in introspection

5. Reflect the main method

Student class:

package fanshe.main;
 
public class Student {
 
	public static void main(String[] args) {
		System.out.println("Main method executes..."); }}Copy the code

The test class:

package fanshe.main;
 
import java.lang.reflect.Method;
 
/** * Get the main method of the Student class, not to be confused with the current main method */
public class Main {
	
	public static void main(String[] args) {
		try {
			// get the bytecode of Student
			Class clazz = Class.forName("fanshe.main.Student");
			
			// get the main method
			 Method methodMain = clazz.getMethod("main", String[].class);// First argument: method name, second argument: method parameter type,
			//3. Call main
			// methodMain.invoke(null, new String[]{"a","b","c"});
			 The first argument, the object type, is null because the method is static, and the second argument is a String array, which is an array in jdk1.4 and a mutable argument after jdk1.5
			 New String[]{"a","b","c"}; So you have to force it.
			 methodMain.invoke(null, (Object)new String[]{"a"."b"."c"});/ / way
			// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}}); 2 / / way
			
		} catch(Exception e) { e.printStackTrace(); }}}Copy the code

Execution Result:

The main method executes...Copy the code

6. Other uses of the reflection method – running configuration file contents through reflection

Student class:

public class Student {
	public void show(a){
		System.out.println("is show()"); }}Copy the code

The configuration file TXT is used as an example (pro.txt) :

className = cn.fanshe.Student
methodName = show
Copy the code

The test class:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
 
/* * We use reflection and configuration files so that: when the application is updated, there is no need to modify the source code * * we just need to send the new class to the client and modify the configuration file */
public class Demo {
	public static void main(String[] args) throws Exception {
		// Get the Class object by reflection
		Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"
		//2 Get the show() method
		Method m = stuClass.getMethod(getValue("methodName"));//show
		//3. Call show()
		m.invoke(stuClass.getConstructor().newInstance());
		
	}
	
	// This method takes a key and gets the corresponding value in the configuration file
	public static String getValue(String key) throws IOException{
		Properties pro = new Properties();// Get the object of the configuration file
		FileReader in = new FileReader("pro.txt");// Get the input stream
		pro.load(in);// Load the stream into the profile object
		in.close();
		return pro.getProperty(key);// Returns the value obtained by key}}Copy the code

Execution Result:

is show(a)
Copy the code

Requirements: When we update the system and write a new Student2 class instead of Student, all we need to do is change the pro.txt file. The code doesn’t change at all

Student2 class to replace:

public class Student2 {
	public void show2(a){
		System.out.println("is show2()"); }}Copy the code

Configuration file changed to:

className = cn.fanshe.Student2
methodName = show2
Copy the code

Execution Result:

is show2(a);
Copy the code

7. Other uses of the reflection method – passing generic checks by reflection

Generics are used at compile time, after which they are erased. So it’s possible to get past the generic check by reflection

The test class:

import java.lang.reflect.Method;
import java.util.ArrayList;
 
For example: If I have a set of String generics, how can I add a value of type Integer to the set? * /
public class Demo {
	public static void main(String[] args) throws Exception{
		ArrayList<String> strList = new ArrayList<>();
		strList.add("aaa");
		strList.add("bbb");
		
	//	strList.add(100);
		// Get the Class object of ArrayList and call add() in reverse to add data
		Class listClass = strList.getClass(); // Get the bytecode object of the strList object
		// Get the add() method
		Method m = listClass.getMethod("add", Object.class);
		// Call add()
		m.invoke(strList, 100);
		
		// iterate over the collection
		for(Object obj : strList){ System.out.println(obj); }}}Copy the code

Execution Result:

aaa
bbb
100
Copy the code

annotations

Overview of annotations

Annotation is a very important topic in Java, but it is often a bit difficult for beginners to understand.

In my opinion, one of the main characteristics of bad technical documentation is the use of technical terms to introduce technical terms. Such as:

Java annotations are used to provide metadata to Java code. As metadata, annotations don’t directly affect your code execution, but there are some types of annotations that can actually be used for this purpose. Java annotations were added to Java starting with Java5. These are Java annotations on most websites, and the explanation is true, but to be honest, when I first learned it, my mind went blank. What the hell is that? I heard it like I didn’t. Because the concept is too abstract, so beginners are really more difficult to understand, and then with their own development process constantly strengthen the practice, will slowly form a correct understanding of it.

As I write this, I am thinking. How can YOU make yourself or your readers more intuitive about the concept of annotations? Do you want to translate instructions on official documents? I immediately rejected the answer.

Later, I thought of something ———— ink, ink can be volatile, can be different colors, used to explain the annotations just right.

But as I continued to think, I came up with a better substitute for ink: a seal. The seal can be stained with different inks or prints, the words or patterns of the seal can be customized, and it can be poked on any surface you wish.

However, as I continued my thinking, I came up with a better alternative to a seal: a tag. A label is a convenience paper, and the contents of the label can be defined freely. Common ones are commodity price tags on shelves, book code labels in libraries, names and categories of chemical materials in laboratories, and so on.

And, to put it abstractly, a label is not necessarily a piece of paper, it can be an attribute evaluation of people and things. In other words, labels have an interpretation of abstract things.

So, with that in mind, I completed my knowledge upgrade, and I decided to annotate with labels.

Annotations as labels

Before, some news client comments had the habit of building a building, so “Jobs redefined the mobile phone, Luo Yonghao redefined the silly X” often very neatly appeared in the comment floor, and the majority of netizens in a quite long period of time for this kind of behavior never tired. This is the equivalent of labeling. In the eyes of some netizens, Luo yonghao has become a synonym for silly X.

The broad masses of netizens to Mr Luo to stick a label called “silly x”, they don’t really know Mr Luo, don’t know him as a teacher, hit the feat of refrigerator, blogging, but because of “dumb” tag, which would help them directly to Mr Luo this man quickly make evaluation, and then based on this, Mr Luo can become in dinner conversation, That’s the power of labels.

On the other side of the network, Luo relies on his personality charm to naturally gain a large number of loyal fans, they stick to luo is another label.

I don’t want to evaluate either behavior, but let me give you another example.

“Science says” is very popular on the Internet debate in recent years, the debater Ming Chen was another debater wei-wei ma attack say – “stand in the center of the universe called love”, and then a big label – – “the man with the chicken soup”, since then, the audience to see Ming Chen, the first thing in my mind is “chicken soup” three characters, In fact, Chen Ming is very good as a teacher, decent style, decent manners, but in the network, because of the environment of entertainment first, people are more willing to take the attitude of entertainment to recognize everything, so “chicken soup man” as Chen Ming himself said has become an inseparable label.

We can generalize abstractly, label is the evaluation and explanation of certain Angle of the behavior of things.

Here, finally can lead to the main notes of this article.

A beginner can think of annotations this way: think of code as living. A annotation is a label attached to some living individual in the code. In a nutshell, a annotation is like a label.

Before you start learning the syntax of any annotations, you can think of a annotation as a label. This will help you quickly understand what it does in general. If the beginner has a blank in the learning process, please don’t panic, say to yourself:

Annotations, labels. Annotations, labels.

Syntax of annotations

Because the common development is rare, I believe that many people will think that the status of annotations is not high. Annotations are of a type, just like classs and interfaces. It was introduced in Java SE 5.0.

Definition of annotations

Annotations are defined by the @interface keyword.

public @interface TestAnnotation {
}
Copy the code

It looks like an interface, but with an @ sign in front of it. The above code creates an annotation named TestAnnotaion.

You can simply create a label named TestAnnotation.

Application of annotations

The above created an annotation, so how to use the annotation is what.

@TestAnnotation
public class Test {}Copy the code

To annotate the class with TestAnnotation, create a class Test and add @testannotation to the class definition.

This can be interpreted as simply adding the notation tag to the Test class.

However, for annotations to work properly, a new concept needs to be introduced: meta-annotations.

Yuan notes

What does a meta-annotation mean?

A meta-comment is a comment that can be added to a comment, or a meta-comment is a basic comment that can be applied to other comments.

If it’s hard to understand, you can understand it like this. A meta-annotation is also a tag, but it is a special tag whose function and purpose is to explain other common tags.

Meta labels include @Retention, @documented, @target, @Inherited, and @REPEATable.

@Retention

Retention Retention means Retention period. When @Retention is applied to a annotation, it explains the annotation’s lifetime.

Its values are as follows:

  • The retentionPolicy.source annotation is only retained at the SOURCE stage and is discarded and ignored when the compiler compiles.
  • The retentionPolicy.class annotation is only retained until compilation and is not loaded into the JVM.
  • Retentionpolicy.runtime annotations can be retained until the application is run, and they are loaded into the JVM, so they can be retrieved while the application is running.

We can deepen our understanding by saying that @Retention specifies when a label is interpreted, it specifies when the label is posted. @Retention is the equivalent of stamping a label with a time stamp that specifies the period in which the label was posted.

@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
Copy the code

@Documented

As the name implies, this meta-annotation must be related to the document. It provides the ability to include elements from annotations into Javadoc.

@Target

Target means Target, and @target specifies where the annotation should be used.

As you can see, when an annotation is annotated by @target, the annotation is restricted to the context in which it is used.

By analogy, tags can be posted anywhere you want, but thanks to @target, they can only be posted to methods, classes, method parameters, and so on. At sign Target has the following values

  • Elementtype. ANNOTATION_TYPE Annotates an annotation
  • Elementtype. CONSTRUCTOR can be annotated to a CONSTRUCTOR
  • Elementtype. FIELD can be used to annotate attributes
  • Elementtype. LOCAL_VARIABLE can be used to annotate local variables
  • ElementType.METHOD can annotate methods
  • Elementtype. PACKAGE can annotate a PACKAGE
  • Elementtype. PARAMETER can be used to annotate parameters within a method
  • Elementtype. TYPE can annotate a TYPE, such as a class, interface, or enumeration

@Inherited

Inherited means Inherited, but it does not mean that the annotations themselves can be Inherited. It means that if a superclass is annotated by @Inherited annotations, then if its subclass is not applied by any annotations, it inherits the superclass’s annotations. It’s more abstract. Code to explain.

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
Copy the code

When Inherited, class A Inherited Test, class B Inherited Test, class B Inherited Test.

It can be interpreted as follows:

Lao Tzu is very rich, so people give him a label called rich.

When Lao Tze’s son grows up, as long as he does not break off the father-son relationship with Lao Tze, although others do not label him, he is naturally rich.

My grandson grew up, of course, also rich.

These are the so-called rich generation, rich second generation, rich third generation. Although the name is different, like a lot of labels, but in fact, the essence of the matter is that they have a common label, that is, laozi’s rich label.

@Repeatable

Repeatable means Repeatable. Repeatable @repeatable was added to Java 1.8, so it’s a new feature.

What annotations are used more than once? Usually the value of an annotation can be multiple at the same time.

Take, for example, a person who is a programmer, a product manager, and a painter.

@interface Persons {
    Person[]  value();
}
@Repeatable(Persons.class)
@interface Person{
    String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{}Copy the code

Notice the code above, @REPEATable annotates Person. The class in parentheses after @REPEATable is equivalent to a container annotation.

What are container annotations?

It’s a place to store other notes. It is a note in itself.

Let’s look again at the relevant container annotations in the code.

@interface Persons {
    Person[]  value();
}
Copy the code

As specified, it must have a value property in it. The property type is an array of annotations annotated by @REPEATable. Note that it is an array.

If it’s hard to understand, you can understand it this way. Persons is a generic tag filled with Person tags of the same type but with different content. To label Persons as SuperMan is to label him as programmer, product manager and painter.

We may be interested in the parenthesis of @person (role= “PM”), which essentially assigns the role attribute of the annotation to PM.

Attributes of annotations

Attributes of annotations are also called member variables. Annotations have only member variables and no methods. An annotation’s member variable is declared in the annotation definition as a method of invisible parameters, whose method name defines the name of the member variable, and whose return value defines the type of the member variable.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    int id(a);
    String msg(a);
}
Copy the code

The code above defines the TestAnnotation annotation that has the ID and MSG attributes. When used, we should assign values to them.

This is done by enclosing the annotation in parentheses with the form value= “”, separated from multiple attributes by a comma.

@TestAnnotation(id=3,msg="hello annotation")
public class Test {}Copy the code

Note that the type of an attribute defined in an annotation must be the eight basic data types plus classes, interfaces, annotations, and their arrays.

Attributes in annotations can have default values, which need to be specified with the default key value. Such as:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id(a) default- 1;
    public String msg(a) default "Hi";
}
Copy the code

The default value of the ID attribute in TestAnnotation is -1 and the default value of the MSG attribute is Hi. It can be applied like this.

@TestAnnotation()
public class Test {}
Copy the code

There is no need to assign the notation inside the parentheses following the @testannotation notation because there are default values. This step can be omitted.

And there’s another situation. If an annotation contains only one attribute named value, you can apply the annotation directly to the attribute value in parentheses.

public @interface Check {
    String value(a);
}
Copy the code

In the code above, the Check annotation only has the value attribute. So you can apply it this way.

@Check("hi")
int a;
Copy the code

It’s the same effect as down here

@Check(value="hi")
int a;
Copy the code

Finally, note that an annotation has no attributes. Such as

public @interface Perform {}
Copy the code

So when applying this annotation, the parentheses can be omitted.

@Perform
public void testMethod(a){}
Copy the code

Java preconfigured annotations

With this knowledge, we can now define our own annotations. The Java language itself already provides several annotations.

@Deprecated

This element is used to mark obsolete elements, which you might encounter in your daily development. When the compiler encounters this annotation at compile time, it will issue a reminder warning that the developer is calling an outdated element such as an outdated method, an outdated class, or an outdated member variable.

public class Hero {
    @Deprecated
    public void say(a){
        System.out.println("Noting has to say!");
    }
    public void speak(a){
        System.out.println("I have a dream!"); }}Copy the code

Defines a Hero class that has two methods say() and speak(), where say() is annotated by @deprecated. We then call them separately from the IDE.

As you can see, the say() method is crossed with a line, which is essentially a reminder of the compiler’s recognition.

@Override

This should be familiar, reminding subclasses to Override the @override method in their parent class

@SuppressWarnings

Prevent warning meaning. As mentioned earlier, the compiler will warn you when calling a method annotated by @deprecated, and sometimes developers will ignore this warning. They can do this by calling @SuppressWarnings from where they were called.

@SuppressWarnings("deprecation")
public void test1(a){
    Hero hero = new Hero();
    hero.say();
    hero.speak();
}
Copy the code

@SafeVarargs

Parameter safety type annotations. Its purpose is to warn developers not to do anything unsafe with arguments, and its existence prevents compilers from generating such warnings. It was added in version 1.7 of Java.

@SafeVarargs // Not actually safe!
    static void m(List<String>... stringLists) {
    Object[] array = stringLists;
    List<Integer> tmpList = Arrays.asList(42);
    array[0] = tmpList; // Semantically invalid, but compiles without warnings
    String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
Copy the code

In the above code, no errors are reported at compile time, but ClassCastException is thrown at runtime, so it tells the developer to take care of it, but the developer is still screwing up.

Future versions will authorize the compiler to issue error warnings about unsafe operations, according to official Java documentation.

@FunctionalInterface

Functional interface annotations, a new feature introduced in Java 1.8. Functional programming is hot, so Java 8 added this feature just in time.

A Functional Interface is a plain Interface with a method. Such as

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run(a);
}
Copy the code

The Runnable we use in threaded development is a typical FunctionalInterface annotated by @functionalinterface.

One might wonder why functional interface tags are useful, because functional interfaces can be easily converted to Lambda expressions. This is another topic, if you are interested, please search for related knowledge points to learn.

Annotation extraction

The previous section of this post covered the basic syntax of annotations, and now it’s time to examine what we’ve learned.

I’m comparing annotations with tags, and the previous section is about how to write annotations and where to post them, and now what we’re going to do is review the tags. The figurative metaphor is that you tear off these annotations at the right time and review the information on them.

The only way to properly review annotations is through reflection.

Annotations and reflections

Annotations are obtained by reflection. You can first determine whether an annotation is applied to a Class object using the isAnnotationPresent() method

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
Copy the code

The Annotation object is then obtained using the getAnnotation() method.

 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
Copy the code

Or getAnnotations().

public Annotation[] getAnnotations() {}
Copy the code

The former method returns the annotations of the specified type, and the latter method returns all annotations annotated to the element.

If the annotations you get are not null, then you can call their property methods. Such as

@TestAnnotation()
public class Test {
    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg()); }}}Copy the code

Execution Result:

id:-1
msg:
Copy the code

This is the default value for ID and MSG in TestAnnotation.

In the example above, we just check out the annotations on the class, but the annotations on the properties and methods are still ok. Again, it’s a reflex.

@TestAnnotation(msg="hello")
public class Test {
    @Check(value="hi")
    int a;
    @Perform
    public void testMethod(a){}
    @SuppressWarnings("deprecation")
    public void test1(a){
        Hero hero = new Hero();
        hero.say();
        hero.speak();
    }
    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            // Get class annotations
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            // Get an annotation on a member variable
            Check check = a.getAnnotation(Check.class);
            if( check ! =null ) {
                System.out.println("check value:"+check.value());
            }
            Method testMethod = Test.class.getDeclaredMethod("testMethod");
            if( testMethod ! =null ) {
                // Get the annotation in the method
                Annotation[] ans = testMethod.getAnnotations();
                for( int i = 0; i < ans.length; i++) { System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName()); }}}catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch blocke.printStackTrace(); System.out.println(e.getMessage()); }}}Copy the code

Execution Result:

id:-1
msg:hello
check value:hi
method testMethod annotation:Perform
Copy the code

Note that @Retention(retentionPolicy.runtime) is required if an annotation is to be successfully extracted at RUNTIME.

Usage scenarios for annotations

I’m sure all of you are familiar with annotations at this point in this post, but many of you are asking, what are annotations really for?

Yeah, what’s the point of a note?

Let’s take a look at the official Java documentation.

At the beginning of this article, I used tags as an analogy for annotations. But the label metaphor is a means to me, not an end. So that you can learn annotations for the first time without being overwhelmed by new abstract concepts. Now that we know about annotations, we might as well take a closer look at the most official documentation.

Annotations are a set of metadata that provides data to interpret program code, but annotations are not part of the interpreted code itself. Annotations have no direct effect on how the code works.

Annotations have many uses, mainly as follows:

  • Provide information to the compiler: The compiler can use annotations to detect errors and warnings
  • Compile-time processing: Software tools can be used to generate code, Html documents, or other processing using annotation information.
  • Runtime processing: Some annotations can be extracted from the code while the program is running. It is important to note that annotations are not part of the code itself.

If it’s hard to understand, look at it this way. Luo Yonghao is still Luo Yonghao, will not change because some people for his “stupid X” evaluation, the label is just some people for other things, but the label does not change the thing itself, the label is only a means of specific groups of people. So again, annotations don’t change the code itself; annotations are just tools of some tool.

Back to the official documentation, annotations are mainly for compilers and other SoftWare tools.

When the developer modiifies the class, method, Field and other members with annotations, these annotations will not take effect by themselves. The developer must provide the corresponding code to extract and process Annotation information. These codes that extract and process annotations are called APT (Annotation Processing Tool).

Now, we can answer for ourselves, what is the use of annotations? For who? For compiler or APT.

If you’re still confused, I’ll write one myself.

Personally customize annotations to accomplish a purpose

I want to write a testing framework to test programmers for obvious anomalies in their code.

Programmer A: I wrote A class called NoBug because all its methods are error-free. Me: Confidence is a good thing, but just in case of accidents, how about I put it to the test? — Programmer A: How do you test it? Me: Just add @jiecha to all the methods you write. — Programmer A: Ok.

package ceshi;
import ceshi.Jiecha;
public class NoBug {
    @Jiecha
    public void suanShu(a){
        System.out.println("1234567890");
    }
    @Jiecha
    public void jiafa(a){
        System.out.println("1 + 1 ="+1+1);
    }
    @Jiecha
    public void jiefa(a){
        System.out.println("1-1 ="+ (1-1));
    }
    @Jiecha
    public void chengfa(a){
        System.out.println("3 x 5="+ 3*5);
    }
    @Jiecha
    public void chufa(a){
        System.out.println("6/0 ="+ 6 / 0);
    }
    public void ziwojieshao(a){
        System.out.println("My program is bug-free!"); }}Copy the code

In the code above, some of the methods use the @jiecha annotation.

This annotation is defined in the test software framework I wrote.

package ceshi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {
}
Copy the code

Then, I’ll write a test class called TestTool to test the NoBug method.

package ceshi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestTool {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        NoBug testobj = new NoBug();
        Class clazz = testobj.getClass();
        Method[] method = clazz.getDeclaredMethods();
        // To record the log information generated by the test
        StringBuilder log = new StringBuilder();
        // Record the number of exceptions
        int errornum = 0;
        for ( Method m: method ) {
            // Only methods annotated by @jiecha are tested
            if ( m.isAnnotationPresent( Jiecha.class )) {
                try {
                    m.setAccessible(true);
                    m.invoke(testobj, null);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                    errornum++;
                    log.append(m.getName());
                    log.append("");
                    log.append("has error:");
                    log.append("\n\r caused by ");
                    // Record the name of the exception that occurred during the test
                    log.append(e.getCause().getClass().getSimpleName());
                    log.append("\n\r");
                    // Record specific information about exceptions that occur during the test
                    log.append(e.getCause().getMessage());
                    log.append("\n\r");
                } 
            }
        }
        log.append(clazz.getSimpleName());
        log.append(" has ");
        log.append(errornum);
        log.append(" error.");
        // Generate a test reportSystem.out.println(log.toString()); }}Copy the code

Execution Result:

1234567890
1+1=11
1-1=0
3 x 5=15
chufa has error:
  caused by ArithmeticException
/ by zero
NoBug has  1 error.
Copy the code

The chufa() method in the NoBug class has an exception called ArithmeticException because it divides 0.

So, the NoBug class is buggy.

Thus, with annotations I accomplish my own purpose, which is to test someone else’s code.

So, ask me again when are annotations used? All I can tell you is, it depends on what you want to do with it.

Annotation Application Example

JUnit is a testing framework, typically used in the following ways:

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect(a) throws Exception {
        assertEquals(4.2 + 2); }}Copy the code

@test marks the method to be tested with addition_isCorrect().

The SSM framework, for example, uses a lot of annotations.

JavaSE phase comes to an end, I hope this Java foundation notes can make more people a deep understanding of Java foundation, and a quick start! I wish you a bright future!