** Digression: ** The Blue silver King is awake!! — from a Douluo mainland animation lover (goose, dozen money!)

Captain came home these days and did something important. When he came back, my brother was still reluctant to let me go back to Beijing. He was still in primary school

Let’s review the previous article on concurrency:

  • Read this introduction to concurrency first

  • Five minutes to get you started on the thread

  • Thread class and Runnable interface source analysis

Why are we only talking about Synchronized, Volatile, and Final? This is not to say that other keywords are not important, but they are the easiest to ask in an interview, and they are also important. Understanding how they work and how they work will help you in your job search

First, let’s briefly introduce what these three are doing:

  • Synchronized is a lock keyword. Every object in Java can be used as a lock to solve the concurrent access problems involved in multi-threaded access. As lock performance is optimized, a lock has four states, ranked from lowest to highest: no state, biased lock state, lightweight lock state, and heavyweight lock state

  • The Volatile keyword can also be used to address thread-safety issues in multithreading. It can be used to modify variables, ensuring visibility and order, but not atomicity

  • The Final keyword is used to ensure immutability. It can be used to modify classes, methods, and variables (including member variables and local variables). The modified class means that they cannot be inherited, and the modified method means that they cannot be overridden

This article is just to let you learn the use of these three keywords, as for more details of the principle I will introduce respectively, first to know why, and then know why

The Synchronized keyword

Synchronized has always been the patriarchy of multithreaded concurrent programming. We used to call it heavyweight locking, but with Java SE1.6 optimization of this keyword, partial locking and lightweight locking were introduced, as well as the storage structure and upgrade process of locks

There are four lock states, ranked from lowest to highest: no lock state, biased lock state, lightweight state, and heavyweight state, which are gradually upgraded with the competition situation. Locks can be upgraded but cannot be downgraded, meaning biased locks cannot become biased locks after being upgraded to lightweight.

This policy of upgrading rather than degrading the lock is intended to improve the efficiency of lock release and release

Synchronized is generally used in the following scenarios:

Excerpt from ** The Art of Concurrent Programming in Java **

Let’s look at a concrete example:

  • For normal methods, the current instance object is locked

    public class SynchronizedTest { public synchronized void getGirl() { }}

  • For statically synchronized methods, the Class object of the current Class is locked

    public class SynchronizedTest { public void getGirl() { synchronized (SynchronizedTest.class) { } }}

  • For Synchronized method blocks, objects configured in Synchronized parentheses are locked

    public class SynchronizedTest { public void getGirl() { synchronized (new Girl()) { } }}

Locking can be implemented using the JVM keyword Synchronized, or we can use the JDK Lock interface to implement locking, but there are some differences between the two

  • Synchronized is a key provided by the JVM and automatically releases the lock; The Lock interface is provided by the JDK and requires us to release the Lock manually

  • Synchronized can lock methods or blocks of code, whereas lock interfaces can only lock blocks of code

  • Synchronized cannot be interrupted, and the lock interface can be interrupted or not interrupted. The lock interface can also know whether the thread has acquired the lock, but the synchronized keyword cannot

  • Synchronized is an unfair lock. The implementation class of the lock interface can control whether the lock is fair or not. It can also improve efficiency by using read/write locks

Which is better? All good (duh!) In the actual use process, we need to analyze which one is good and which one is more appropriate according to the business.

The Volatile keyword

Volatile is a type specifier designed to modify variables that are accessed and modified by different threads. Volatile **** is used as an instruction key to ensure that the instruction is not omitted for compiler optimization and requires direct reads each time

We typically use the volatile keyword to modify a variable, and then write to the variable with visibility. Visibility means that if one thread changes the value of the variable, other threads will immediately see the value

Let’s look at an example:

Normally we would expect the main thread to start a new thread, incrementing the counter until the main thread flag is set to true

After the main thread sleeps for one second, flag is set to true, at which point the testThread child thread should detect and jump out of the loop, so we expect to see the effect stop after one second and print the actual value

Then we found that it went into an infinite loop, and in task Manager we found that the CPU usage of the Java program skyrocketed

What’s going on?

In the Java Memory model, the Java memory model has main memory and working memory. The variables in the main memory are shared by all threads. Each thread has its own working memory, and the variables in the main memory contain thread-local variables. If a variable in main memory is used by a thread, the thread copies it to its working memory, which maintains a copy of the main memory variable

Therefore, the sub-thread will not immediately detect the flag variable that causes the modification of the main thread, because the sub-thread has its own working memory and has a copy. All the read and write operations of the variable must be carried out in the working memory by the thread, and the variables in the main memory cannot be directly operated

We add the volatile flag variable to the flag variable and find that the dead loop disappears because the main thread changes the volatile flag bit to invalidate the working memory copy of the child thread immediately and flush it to the main memory

The Final keyword

The final keyword is used to modify ** classes, ** member variables, and member methods.

Let’s take a look at each:

  • When final decorates a class, it means that the class is not inheritable

Class FinalTest () {FinalTest () {FinalTest ();

  • When final modifies a member variable, the initial value must be assigned (directly or ina constructor) and cannot be changed

When we try to modify the final value:

  • Final cannot be overridden when modifying member methods

Test_final (); test_final ();

Error found that a function representing a final modifier cannot be overridden

Say two **** questions we think about (final solution) :

1. Why break the rules with final when you design inheritance? 2. What are the differences between final, finally and Finalize? (Often asked in an interview)

Do you understand the final keyword? Let’s think about a question

public class Main {   public static void main(String[] args) {       String a = "shixiong2";       final String b = "shixiong";       String d = "shixiong";       String c = b + 2;       String e = d + 2;       System.out.println((a == c));       System.out.println((a == e));   }}
Copy the code

Think about that for yourself. Think about why

The problems mentioned above will be explained in detail in the final chapter

Flocculant on

The more you know, the more you don’t know.

Didi: These keywords must be learned, not master can pay attention to my article, I will insist on sharing technical articles ~