[JUC] 1. synchronized keyword and Lock interface

Article directory

  • 1. JUC
  • 2. Processes and threads
  • 3. Concurrency and parallelism
  • 4. User thread and daemon thread
  • 5. Object locks and class locks
  • 6. Synchronized keyword
  • 7. synchronized case
  • 8. Lock interface

1.JUC

JUC, the java.util.concurrent toolkit for processing threads, started with JDK1.5, and has three packages:

  • Basic package
  • Atomic package
  • Lock bag

2. Process and thread

The relationship between processes and threads:

  • A process is an application (a process is a software)
  • A thread is an execution scenario/execution unit in a process. A process can start multiple threads

Think of Process as a real-life company, such as JD.com. A thread can be regarded as a functional department under it, responsible for completing a certain task, such as the development department.

for example:

To run java HelloWorld in a DOS window, first start the JVM. The JVM is a process. The JVM starts a main thread to call the main method, and at the same time starts a garbage collection thread to take care of and collect garbage. (That is to say, the Java program must have at least two concurrent threads, the main thread corresponding to the main method + GC)

Memory relationship between process A and process B:

In Java, thread A and thread B share heap memory and method area memory, but the stack memory is independent, one thread has one stack. If 10 threads are started, there will be 10 stack spaces. Each stack does not interfere with each other and each executes its own task. This is multi-thread concurrency.

for example:

The purpose of the multi-threading mechanism in Java is to improve the processing efficiency of the program. For example, the train station is regarded as a process, then each small ticket sales window is a thread. A buys in window 1 For tickets, B buys tickets at window 2. No one has to wait for anyone. Each ticket window is like a stack, with its own independent space. The shared space of the ticket hall is like the heap and method area

3. Concurrency and parallelism

Let’s talk about serial and parallel first:

  • The serial mode is to only take one task at a time and execute this task. For example, a truck of firewood must be loaded before it can be transported. Only after it is delivered, can the truck of firewood be unloaded. Only when one step is completed can you move on to the next step.
  • Parallel mode allows you to fetch multiple tasks at the same time and execute the fetched tasks at the same time.

And Parallel and concurrency is:

  • Concurrency: At the same time, multiple threads are accessing the same resource, and multiple threads are accessing one point. Corresponding examples: Spring Festival travel ticket grabs, e-commerce flash sales

  • Parallel: perform multiple tasks at the same time, and then summarize the examples. For example, make instant noodles, boil water in an electric kettle, and pour the seasoning into a bucket.

4. User thread and daemon thread

Threads in Java are divided into two categories:

  • User-defined threads, such as the main thread, or other customized threads
  • Daemon thread: such as garbage collection thread. Generally, the daemon thread is an infinite loop. When all user threads end, the daemon thread automatically ends.

Write a test code:

public static void main(String[] args){<!-- -->

Thread aa = new Thread( () -> {<!-- -->
\t\t
System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
while (true) {<!-- -->
\t\t
}
}, "aa");
aa.setDaemon(true);
aa.start();
System.out.println(Thread.currentThread().getName() + " over");
}

It can be seen that when aa.setDaemon(true) is annotated, the aa thread belongs to the user-defined thread. After the main thread ends, the customized aa thread is not affected and the JVM continues to survive:

After the aa thread is set as a daemon thread, when all user threads end, the daemon thread automatically ends:

5. Object lock and class lock

A lock is a tool that controls multiple threads' access to shared resources. Typically, a lock provides exclusive access to a shared resource. Only one thread can acquire a lock at a time, and all access to a shared resource requires first acquiring the lock. However, some locks may allow concurrent access to shared resources, such as ReadwriteLock’s read lock.

  • Class locks belong to a class, similar to static variables. Multiple instance objects correspond to the same lock, one lock for each class.
  • Object locks belong to object instances, similar to class attribute variables. Each instance object corresponds to a lock. There are 100 object locks for 100 objects of class A.

6. Synchronized keyword

synchronized is a Java keyword that represents a synchronization lock. This keyword:

  • Modifiable code blocks, the scope is the statements in curly brackets, and the target object is the object that calls this code block
synchronized(thread shared object){<!-- -->
…
//Thread synchronization code block, that is, the code block to be queued for execution
…

}
  • Modifiable methods, the scope is the entire method, and the object is the object that calls this method
public synchronized void doSome(){<!-- -->
//...
}
  • Using synchronized in an instance method means that the shared object must be this, and the synchronized code block is the entire method body.
  • Using synchronized in a static method means looking for a class lock. There is always only one class lock (object lock means there are 100 object locks for 100 objects).

7. Synchronized case

Steps of multi-threaded programming

  • Step 1: Create resource classes (to be shared in the future), create attributes and operation methods
  • Step 2: Perform in the operation method of the resource class: judge, work, and notify
  • Step 3: Create a method for calling resource classes from multiple threads
  • Step 4: Prevent false wake-ups

Simulate three ticket sellers selling 30 tickets at the same time. The three ticket sellers, that is, three threads, the resource class is the ticket class, and the attribute of the resource class is the number of tickets:

//Resource class
class Ticket{<!-- -->

    private Integer number = 30;

    public synchronized void sale(){<!-- -->
        if(number > 0 ){<!-- -->
            System.out.println(Thread.currentThread().getName() + ": Sold tickets, remaining" + number--);
        }
    }
}

Open three threads and call methods in the resource class:

public class SaleTicket {<!-- -->

    public static void main(String[] args) {<!-- -->
    //Multiple threads share this resource object
        Ticket ticket = new Ticket();
        new Thread(() -> {<!-- -->
            for(int i = 0; i < 40; i + + ){<!-- -->
                ticket.sale();
            }
        },"AA").start();

        new Thread(new Runnable() {<!-- -->
            @Override
            public void run() {<!-- -->
                for(int i = 0; i < 40; i + + ){<!-- -->
                    ticket.sale();
                }
            }
        },"BB").start();
        Thread cc = new Thread(() -> {<!-- -->
            for (int i = 0; i < 40; i + + ) {<!-- -->
                ticket.sale();
            }
        }, "CC");
        cc.setPriority(Thread.MAX_PRIORITY);
        cc.start();
    }


}


</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">

8. Lock interface

API documentation:

https://tool.oschina.net/apidocs/apidoc?api=jdk-zh

The Lock interface is more flexible than synchronized. Its implementation classes are:

  • ReentrantLock
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

ReentrantLock can be used to re-enter the lock, analogous to queuing to go to the toilet, locking the door after entering, unlocking after use, the next person continues to lock, and unlocks after use.

class X {<!-- -->
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {<!-- -->
     lock.lock(); // block until condition holds
     try {<!-- -->
       // ... method body
     } finally {<!-- -->
       lock.unlock()
     }
   }
 }

Comparison of Lock interface and synchronized:

  • Lock is an interface with corresponding implementation classes, and synchronized is a Java keyword
  • Synchronized does not require the user to manually release the lock. When the execution of a synchronized code block or method ends or an exception occurs, the system will automatically let the thread release the lock, while Lock requires developers to manually release the lock.
  • Lock can make the thread waiting for the lock respond to the terminal, but synchronized cannot, the waiting thread will wait forever.
  • Lock can wait until the lock is successfully acquired, but synchronized cannot
  • Lock can refer to the efficiency of multiple threads performing read operations.
  • When a large number of threads compete fiercely at the same time, Lock performance is far better than synchronized

Use Lock to implement the ticket selling example of the previous synchronized implementation:

//Resource class
class LTicket{<!-- -->

    private Integer number = 30;

    private final ReentrantLock lock = new ReentrantLock();

    public void sale(){<!-- -->
        //Lock
        lock.lock();
        try {<!-- -->
            if( number > 0 ){<!-- -->
                System.out.println(Thread.currentThread().getName() + ": Sold tickets, remaining" + number--);
            }

        } finally {<!-- -->
            //Release the lock and write it in the finally statement to prevent the above exception from causing the lock to not be released.
            lock.unlock();
        }
    }
}
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">

Create a shared resource class object and open multiple threads to call the resource class method:

public class LSaleTicket {<!-- -->

    public static void main(String[] args) {<!-- -->
        LTicket ticket = new LTicket();
        new Thread(() -> {<!-- -->
            for(int i = 0; i < 40; i + + ){<!-- -->
                ticket.sale();
            }
        },"AA").start();

        new Thread(new Runnable() {<!-- -->
            @Override
            public void run() {<!-- -->
                for(int i = 0; i < 40; i + + ){<!-- -->
                    ticket.sale();
                }
            }
        },"BB").start();
        new Thread(() -> {<!-- -->
            for (int i = 0; i < 40; i + + ) {<!-- -->
                ticket.sale();
            }
        }, "CC").start();
    }
}

</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">