1. Multithreading basics

1.1 what is a process

Process is a running activity of a program on a data set in a computer. It is the basic unit of resource allocation and scheduling in the system, and the foundation of operating system structure. In the early process-oriented computer architecture, process is the basic execution entity of program. In modern thread-oriented computer architecture, processes are containers for threads. A program is a description of instructions, data and its organizational form, and a process is the entity of a program.

Narrow definition: a process is an instance of a computer program that is being executed. Broad definition: a process is a program with certain independent functions about a data set of a run activity. It is the basic unit of dynamic execution of the operating system. In the traditional operating system, the process is both the basic unit of allocation and the basic unit of execution.

Important concepts

  • Each process has its own address space
  • To make a process switch is to reclaim the processor from the running process and then let the process to be run take over the processor.
  • A single-core CPU can only run one thread at a time, and a process is a container for threads. So you can only run one process.

Scheduling algorithm: Abba abba.

Refer to the address

1.2. What is thread

A thread (in English: thread) is the smallest unit on which an operating system can schedule operations. It is contained within the process and is the actual operating unit in the process. A thread refers to a single sequential flow of control in a process. A process can have multiple threads concurrently, each performing different tasks in parallel. In Unix System V and SunOS, they are also called Lightweight processes, but lightweight processes are more commonly referred to as kernel threads and user threads as threads.

Thread state
  • Create (NEW) : A NEW thread object has been created, but the start() method has not yet been called.
  • RUNNABLE: Java threads generally refer to both ready and running states as “running.”

After a thread object is created, the object’s start() method is called by another thread, such as the main thread. A thread in this state is in the ready state when it is in the runnable thread pool and waiting to be selected by a thread scheduler to gain access to the CPU. A thread in the ready state becomes in the running state after obtaining the CPU time slice.

  • BLOCKED: Indicates that a thread is BLOCKED from a lock.
  • WAITING: The thread in this state is WAITING for some specific action (notification or interruption) from another thread.
  • Timeout wait (TIMED_WAITING) : This state, unlike WAITING, can return after a specified time.
  • TERMINATED: indicates that the thread has finished executing.

Refer to the address

1.3. How to create threads

1.3.1. Inherit from Thread

Steps:

  • Inheriting the Thread
  • Override the run method
  • Create a custom class instance and run the start() method to start the thread.

Example:

public class TestThread extends Thread{ @Override public void run() { Println (String. Format (" currentThread name [%s] ", thread.currentthread ().getname ())); system.out.println (string.format (" currentThread name [%s] ", thread.currentthread ().getname ())); } public static void main(String[] args) { new TestThread().start(); }}Copy the code
1.3.2 Implement the Runnable interface

Steps:

  • Implement the Runnable interface
  • Override the run method
  • Create a custom class instance, create a Thread instance, pass the custom class instance into the Thread instance constructor, and run the start() method to start the Thread.

Example:

public class TestRunnable implements Runnable{ @Override public void run() { Println (String. Format (" currentThread name [%s] ", thread.currentthread ().getname ())); system.out.println (string.format (" currentThread name [%s] ", thread.currentthread ().getname ())); } public static void main(String[] args) { new Thread(new TestRunnable()).start(); }}Copy the code

You can also use lambda expressions to create threads

public static void main(String[] args) { new Thread(()->{ Println (String. Format (" currentThread name [%s] ", thread.currentthread ().getname ())); system.out.println (string.format (" currentThread name [%s] ", thread.currentthread ().getname ())); }).start(); }Copy the code
1.3.3. Implement the Callable interface

Steps:

  • Implements the Callable interface
  • Override the call() method
  • Create a custom class instance, create a FutureTask instance, pass the custom class example to the constructor of the FutureTask instance, create a Thread instance, pass the FutureTask instance to the constructor of the Thread instance, and run the start() method to start the Thread.

Example:

public class TestCallable implements Callable<Integer> { @Override public Integer call(){ String name = Thread.currentThread().getName(); System.out.println(String. Format (" current thread name [%s] ",name)); return 666; } public static void main(String[] args) { FutureTask<Integer> futureTask = new FutureTask<>(new TestCallable()); new Thread(futureTask).start(); try { Integer result = futureTask.get(); System.out.println(string.format (" thread returns %d",result)); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }}}Copy the code

1.4 Thread operations

1.4.1 Thread sleep

** Thread.sleep() method **

This method suspends the Thread returned by Thread.currentThread() for n milliseconds.

Example:

Public static void main(String[] args) throws InterruptedException {system.out.println (" Name of the current thread of execution: "+Thread.currentThread().getName()); Thread.sleep(2000); New Thread(()->{system.out.println () + thread.currentThread ().getName()); }).start(); }Copy the code

The main thread starts first, and then the main thread starts the child thread. Let the main thread sleep for 2 seconds before starting the child thread. If there is no sleep effect, the program will print out “thread name XXX” immediately, and then terminate directly.

Let’s consider a question: ** why is the sleep() method static? 台湾国

I was thinking about why sleep() isn’t unique to each instance, and then using this.sleep() can sleep the instance thread. The sleep() method pauses the thread that is currently running, but there is no guarantee inside the class that the thread is currently running. Let’s test this:

public class ThreadOperate { public static void main(String[] args) { new TestThread1().start(); } public static class TestThread1 extends Thread {static {system.out.println (" Static block Thread name: " + Thread.currentThread().getName()); } @override public void run() {system.out.println (" Thread name: "+ thread.currentThread ().getName()); Thread name: main Thread name: thread-0Copy the code

We find that the static block code is executed by the main thread.

We sometimes look at multithreaded code and see thread.sleep (0); What’s the point of this operation, which is to sleep the thread for 0 seconds? The following link explains what this does and I won’t repeat it.

link

The above link is a bit of a problem, though, because it refers to the old Windows operating system, which is now preemptive multitasking, depriving threads of CPU usage after a period of time. Specific can refer to Baidu encyclopedia link

** Thread.yield() **

The current method causes the executing thread to give up CPU resources. How is it different from sleep?

Yield yields slices of time for the CPU to reschedule, but sleep also yields slices of time for other threads to execute. We can test that out.

Public static void main(String[] args) throws InterruptedException {new Thread(()->{system.out.println (" Name of Thread: " + Thread.currentThread().getName()); }).start(); Thread.sleep(10000); System.out.println(777); }Copy the code

If the thread does not relinquish the time slice, the main thread will hold the execution until the other threads continue to execute, so the order of printing would be “777” first and “thread name” later, but in fact the opposite is true.

So what’s the practical difference?

1, the sleep() method claims to throw InterruptedException; The yield() method does not declare any exceptions. 2. The thread is in the blocked state after executing the sleep() method. The yield() method is executed to enter the ready state. 3, sleep() does not consider the priority of the thread when it gives another thread a chance to run, so it gives the low-priority thread a chance to run; The yield() method gives only threads of the same or higher priority a chance to run.

We don’t know if these conclusions are correct, but we’ll test them when we get to the relevant points.

1.4.2 Thread Interruption

** interrupt() **

We interrupt the thread by interrupt(). It doesn’t actually stop the thread, it just makes a stop sign. We can try:

 public static void main(String[] args) {
        Thread.currentThread().interrupt();
        System.out.println(666);
    }
Copy the code

If it had been the execution of the terminating thread, then “666” would not have been printed, but it was printed, so the thread was not terminated. So why do we have this method? Don’t stop() stop the thread? Well, it’s actually recommended to use the interrupt() method in projects. Why is that?

For example, when a car goes to a car wash, it has to be cleaned both inside and outside. Then the car has arrived at the car wash, the people in the car have not come down, but the clerk has taken the tools to prepare for the car wash, you are ready to people with the car wash, or wash together?

Shop assistant: You don’t have to come down. You can wash it with the car. Salesperson: I’m going to start washing the car. But it hasn’t started, waiting for you to do some other action, such as: people from the car down!

Now that the stopped state is identified, how can we tell if the thread has stopped?

For example, if the Thread isInterrupted() or thread.currentthread () or interrupted(), they are used to obtain the status of the Thread.

The interrupted() method clears the status of the stopped flag, whereas isInterrupted() takes the status directly without clearing it. We can look at the corresponding source:

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

public boolean isInterrupted() {
        return isInterrupted(false);
    }
Copy the code

After the interrupted method has been interrupted, it will clear the status of “thread.currentThread ()”, which is the status of the running Thread.

public static void main(String[] args) { Thread.currentThread().interrupt(); System.out.println(Thread.interrupted()); System.out.println(Thread.interrupted()); Public static void main(String[] args) {thread.currentThread ().interrupt(); System.out.println(Thread.currentThread().isInterrupted()); System.out.println(Thread.currentThread().isInterrupted()); Public static void main(String[] args) {thread.currentThread ().interrupt(); System.out.println(Thread.interrupted()); System.out.println(Thread.currentThread().isInterrupted()); } # print true falseCopy the code

For example, after a interruption (), the interrupt() method will clear the status of the interrupted object, whereas isInterrupted() will not clear the status of the interrupted object. Get the main thread directly). Here’s another one:

public static void main(String[] args){ Thread.currentThread().interrupt(); TestThread1 thread = new TestThread1(); thread.start(); System.out.println(" End of main thread "); System.out.println(Thread.currentThread().isInterrupted()); } public static class TestThread1 extends Thread{ static { System.out.println(Thread.interrupted()); } @override public void run() {system.out.println (" thread is over "); }} # Print true to end the main threadCopy the code

We know that “thread.Interrupted ()” clears the status of the running Thread.

Here’s another question to consider: If a thread interrupts, does it print true or false when the thread stops running? Let’s take a look:

public class ThreadOperate { public static void main(String[] args) throws InterruptedException { TestThread1 thread = new TestThread1(); thread.start(); thread.interrupt(); System.out.println(thread.isInterrupted()); Thread.sleep(3000); System.out.println(thread.isInterrupted()); System.out.println(" End of main thread "); } public static class TestThread1 extends Thread {@override public void run() {system.out.println (); }}} # print: true thread ends false Main thread endsCopy the code

We find that the state is also cleared when the thread ends.

Finally, let’s verify the conclusion from the previous section: the sleep() method declares that it throws InterruptedException; The yield() method declares no exceptions.

public static void main(String[] args) { try { Thread.currentThread().interrupt(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }} # print Java. Lang. InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.rookie.stream.download.thread.ThreadOperate.main(ThreadOperate.java:11) public static void main(String[] args) { try  { Thread.sleep(1000); Thread.currentThread().interrupt(); } catch (InterruptedException e) { e.printStackTrace(); Public static void main(String[] args) {thread.currentThread ().interrupt(); Thread.yield(); }Copy the code

That seems to be a good conclusion.

In essence, interrupt is to mark the clear state, and then to determine the state and do some subsequent cleanup, before manually stopping the thread. For example, in the thread’s run method to determine the status, when the status is true, clean up, and then return to end the thread.

Wait () and notify() **

I’ll just write a title and discuss the details in the “locks” section.

1.4.3 Thread priority

priority

Each thread has a priority, ranging from 1 to 10. The higher the priority, the more likely the thread is to run first. , of course, this has to do with the CPU scheduling, not to say that your priority is higher, you can run priority mission, this is also associated with some time complexity, and so on factors, priority can only be relative to the more priority, let’s look at a few examples:

public static void main(String[] args) { Thread thread1 = new Thread(() -> { for (int i = 0; i < 100; I ++) {system.out.print (String. Format (" thread 1: %d ", I)); }}); Thread thread2 = new Thread(() -> { for (int i = 0; i < 100; I ++) {system.out.print (String. Format (" thread 2: %d ", I)); }}); thread1.setPriority(10); thread2.setPriority(1); thread2.start(); thread1.start(); }Copy the code

The time complexity of the two threads is the same, but the priority of one is the highest and the priority of the other is the lowest.

Thread 2:0 Thread 2:1 Thread 2:2 Thread 2:3 Thread 2:4 Thread 2:5 Thread 1:0 Thread 2:6 Thread 1:1 Thread 2:7 Thread 1:2 Thread 2:8 Thread 1:3 Thread 2:9 Thread 1:4 Thread 2:10 Thread 1:5 Thread 2:11 Thread 1:6 Thread 2: 12 Thread 1:7 Thread 2:13 Thread 1:8 Thread 2:14 Thread 1:9 thread 2:15 Thread 1:10 thread 2:16 Thread 1:11 thread 2:17 Thread 1:12 thread 2:18 Thread 1:13 thread 2:19 Thread 1:14 Thread 2:20 Thread 1: 15 thread 2:21 thread 1:16 thread 2:22 thread 1:17 thread 2:23 thread 2:24 thread 2:25 thread 2:26 thread 2:27 thread 2:28 thread 2:29 thread 2:30 thread 2:31 thread 2:32 thread 2:33 thread 2:34 Thread 2: 35 Thread 2:36 Thread 2:37 thread 2:38 thread 2:39 Thread 2:40 thread 2:41 thread 2:42 thread 2:43 Thread 1:18 thread 1:19 thread 1:20 thread 2:44 thread 1:21 thread 2:45 thread 1:22 thread 2:46 Thread 1: 23 Thread 2:47 thread 1:24 thread 2:48 thread 1:25 thread 2:49 thread 1:26 thread 2:50 thread 1:27 thread 2:51 thread 1:28 thread 2:52 thread 1:29 thread 2:53 thread 1:30 thread 2:54 Thread 1:31 Thread 2: 55 thread 1:32 thread 2:56 thread 1:33 thread 2:57 thread 1:34 thread 2:58 thread 1:35 thread 2:59 thread 1:36 thread 2:60 thread 1:37 thread 2:61 thread 1:38 thread 2:62 thread 1:39 thread 2:63 Thread 1: 40 Thread 2:64 Thread 1:41 Thread 2:65 thread 1:42 thread 2:66 thread 1:43 thread 1:44 thread 1:45 thread 1:46 thread 1:47 thread 1:48 thread 1:49 thread 1:50 thread 1:51 thread 1:52 thread 1:53 Thread 1: 54 thread 1:55 thread 1:56 thread 1:57 thread 1:58 thread 1:59 thread 1:60 thread 1:61 thread 1:62 thread 1:63 thread 1:64 thread 1:65 thread 1:66 thread 1:67 thread 1:68 thread 1:69 thread 1:70 thread 1: 71 Thread 1:72 thread 1:73 thread 1:74 thread 1:75 thread 1:76 Thread 1:77 thread 1:78 thread 1:79 Thread 1:80 Thread 1:81 thread 1:82 thread 1:83 Thread 1:84 Thread 1:86 thread 1:87 thread 1: 88 Thread 1:89 Thread 1:90 Thread 1:91 Thread 1:92 Thread 1:93 thread 1:94 thread 1:95 thread 1:96 Thread 1:97 thread 1:98 thread 2:67 Thread 1:99 thread 2:68 thread 2:69 thread 2:70 thread 2:71 Thread 2: 72 thread 2:73 thread 2:74 thread 2:75 thread 2:76 thread 2:77 thread 2:78 thread 2:79 thread 2:80 thread 2:81 thread 2:82 thread 2:83 thread 2:84 thread 2:85 thread 2:86 thread 2:87 thread 2:88 thread 2: 89 Thread 2:90 thread 2:91 thread 2:92 thread 2:93 thread 2:94 thread 2:95 thread 2:96 thread 2:97 thread 2:98 thread 2:99Copy the code

We find that although we start 2 first, at first 2 runs first and is dominant, and then at 5, the two threads start to switch between each other and the resources appear to be equal. Then 2 takes the lead again, and at 66, thread 1 takes the lead, all the way up until thread 2 finishes the job. Thread 1 executes later, but ends up executing better than thread 2.

Inheritance of priorities

In Java, whoever started it has the same priority as the thread that started it.

public static void main(String[] args) { Thread thread1 = new Thread(() -> { }); Thread thread2 = new Thread(() -> { }); thread2.start(); thread1.start(); System.out.println(Thread.currentThread().getPriority()); System.out.println(string.format (" thread1 priority: %d", thread1.getpriority ())); System.out.println(string.format (" thread2 priority: %d", thread2.getpriority ())); } # Print 5 thread 1 priority: 5 thread 2 priority: 5Copy the code

The output is all 5, with the same priority.

Why does the main thread have priority 5?

Let’s look at the source code:

/**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;
Copy the code

The source code comments indicate that 5 is the default priority.

But does prioritization really determine the outcome?

Let’s look at the following example:

public static void main(String[] args) { Thread thread1 = new Thread(() -> { try { for (int i = 0; i < 10; i++) { Thread.sleep(100); System.out.print(String. Format (" thread 1: %d ", I)); } } catch (InterruptedException e) { e.printStackTrace(); }}); Thread thread2 = new Thread(() -> { try { for (int i = 0; i < 10; i++) { Thread.sleep(50); System.out.print(String. Format (" thread 2: %d ", I)); } } catch (InterruptedException e) { e.printStackTrace(); }}); thread1.start(); thread2.start(); thread1.setPriority(10); thread2.setPriority(5); }Copy the code

Thread 1 starts first and thread 1 starts first.

Thread 2:0 Thread 1:0 Thread 2:1 Thread 2:2 Thread 1:1 Thread 2:3 Thread 2:4 Thread 1:2 Thread 2:5 Thread 2:6 Thread 1:3 Thread 2:7 Thread 2:8 Thread 1:4 Thread 2:9 Thread 1:5 Thread 1:6 Thread 1:7 thread 1:8 Thread 1:9Copy the code

It turns out that thread 1 doesn’t have much of an advantage in timeliness either.

1.5. Thread synchronization

Multithreading can split a task into multiple threads, which is a big time saver, but it can also cause some problems.

For example, the “dirty read” problem. Both threads read the data at the same time, and the data is consistent. However, after one thread changes the data, the other thread does not know that the data has been modified, so it operates on an invalid data. This is the reason for thread insecurity.

We can try this:

public class TestThread { public static int i = 10; public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread1 thread2 = new Thread1(); thread1.start(); thread2.start(); } public static class Thread1 extends Thread{ @Override public void run() { try { while (TestThread.i > 0){ System.out.println(TestThread.i); TestThread.i--; Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

We expected the print-out to be 10-1, but it turned out differently: 10 10 8 8 6 5 4 3 2 1. This is where thread preemption is out of sync (why sleep? Because the print number is too small, prevent a thread to print out). Let’s move on to the next one.

public class TestThread { public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread1 thread2 = new Thread1(); thread1.start(); thread2.start(); } public static class Thread1 extends Thread{ private int i = 10; @override public void run() {try {while (I > 0){system.out.print (String. %d ",Thread.currentThread().getName(),i)); i--; Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); }}}} Print: Thread: thread-0:10 Thread: thread-1:10 Thread: thread-1:9 Thread: thread-0:9 Thread: thread-0:8 Thread: thread-1:8 Thread: thread-0:7 Thread: Thread-1:7 Thread: thread-0:6 Thread: thread-1:6 Thread: thread-0:5 Thread: thread-1:5 Thread: thread-0:4 Thread: thread-1:4 Thread: thread-1:3 Thread: Thread-0:3 Thread: thread-1:2 Thread: thread-0:2 Thread: thread-1:1 Thread: thread-0:1Copy the code

with

public class TestThread { public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread thread2 = new Thread(thread1); Thread thread3 = new Thread(thread1); thread2.start(); thread3.start(); } public static class Thread1 implements Runnable{ private int i = 10; @override public void run() {try {while (I > 0){system.out.print (String. %d ",Thread.currentThread().getName(),i)); i--; Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); }}}} Print: Thread: thread-0:10 Thread: thread-1:10 Thread: thread-1:8 Thread: thread-0:8 Thread: thread-0:6 Thread: thread-1:6 Thread: thread-1:4 Thread: Thread-0:3 Thread: thread-0:2 Thread: thread-1:2Copy the code

Why do two codes that feel similar run so different? Because thread insecurity occurs when multiple threads write to the same resource, the first piece of code each thread operates on its own object, while the second piece operates on the same object.

Then change the code again:

public class TestThread { public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread thread2 = new Thread(thread1); Thread thread3 = new Thread(thread1); thread2.start(); thread3.start(); } public static class Thread1 implements Runnable{ @Override public void run() { int i = 10; Try {while (I > 0){system.out.print (String. Format (" Thread: %s: %d ", thread.currentThread ().getName(), I)); i--; Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); }}}} Print: Thread: thread-0:10 Thread: thread-1:10 Thread: thread-1:9 Thread: thread-0:9 Thread: thread-1:8 Thread: thread-0:8 Thread: thread-1:7 Thread: Thread-0:7 Thread: thread-1:6 Thread: thread-0:6 Thread: thread-1:5 Thread: thread-0:5 Thread: thread-1:4 Thread: thread-0:4 Thread: Thread-1:3 Thread: Thread-0:3 Thread: thread-1:2 Thread: thread-0:2 Thread: thread-1:1 Thread: thread-0:1Copy the code

Because local variables are stored in a storage area unique to each thread and are not visible to other threads, there are no thread-safety issues with local variables.

** Thread unsafe occurs in class variables or instance variables, whereas variables within methods are thread-safe. If there is write while reading, then there may be thread unsafe. Therefore, to ensure thread safety, we must separate the read from the read. There must be no write while reading and no read while writing.

So how do you make it thread-safe?

The first method is synchronized

1.5.1 Object locking
public class SyncThread { public static void main(String[] args) { TestThread1 testThread1 = new TestThread1(); Thread thread1 = new Thread(testThread1); Thread thread2 = new Thread(testThread1); thread1.start(); thread2.start(); } public static class TestThread1 implements Runnable { private int i = 10; Synchronized private void reduce() {try {String text = string.format (" thread: %s print ->%d ", thread.currentThread ().getName(),this.i); System.out.print(text); Thread.sleep(500); this.i--; } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { while (this.i > 0) { reduce(); }}}} print: Thread: thread-1 print ->10 Thread: thread-1 print ->9 Thread: thread-1 print ->8 Thread: thread-1 print ->7 Thread: thread-1 print ->6 Thread: thread-1 print ->5 Thread: Thread-1 print ->4 Thread: thread-1 print ->3 Thread: thread-1 print ->2 Thread: thread-1 print ->1 Thread: thread-0 print ->0Copy the code

Now that’s nice, thread 0 notices that if thread 1 is executing (can’t get the lock), it will wait for thread 1 to finish executing first before executing (releasing the lock). This is an object lock, preceded by the keyword synchronized, because the method is called by the object instance.

Let’s think about this: if there are two synchronized methods A and B in A class and they are both object locks, what happens if one thread accesses method A and gets the object lock, and the other thread accesses method B and executes it?

public class SyncThread { public static void main(String[] args) { TestThread1 testThread1 = new TestThread1(); Thread thread1 = new Thread(testThread1); Thread thread2 = new Thread(testThread1); thread1.start(); thread2.start(); } public static class TestThread1 implements Runnable { private int i = 10; private boolean r = true; synchronized private void reduce() { r = false; Try {String text = string.format ("[Thread] : %s print ->%d ", thread.currentThread ().getName(), this.i); System.out.println(text); Thread.sleep(2000); this.i--; } catch (InterruptedException e) { e.printStackTrace(); }} synchronized private void add() {try {String text = String. Format (" synchronized ") : %s print ->%d ", thread.currentThread ().getName(), this.i); System.out.println(text); Thread.sleep(3000); this.i++; } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { if (r) { reduce(); } else { add(); }}}} print: [Thread] : thread-0 print ->10 [Thread] : thread-1 print ->9Copy the code

We found that when a thread accesses another synchronized method, it is blocked, and the result is printed only when the first thread ends. When add is removed, the second line is printed immediately, so object locking affects access to synchronized methods on the same class. Of course the lock has to be the same (some other issues with R I didn’t consider).

private void reduce() { synchronized (this) { r = false; Try {String text = string.format ("[Thread] : %s print ->%d ", thread.currentThread ().getName(), this.i); System.out.println(text); Thread.sleep(2000); this.i--; } catch (InterruptedException e) { e.printStackTrace(); }}}Copy the code

Synchronized (this){} is equivalent to adding synchronized to the method above, and is also an object lock, locking the current object. However, the following method is more flexible. A lock on a method will lock the entire method block, while a lock on a part of the code will lock a part of the code, and the rest of the code is asynchronous. While the thread is waiting to acquire the lock, it is blocked, that is, no more code is executed until the lock or other operation is acquired.

1.5.2, class lock

Class locks are similar to object locks, except that the object of the lock is changed from an example of the class to the class itself, and the scope of synchronization is much larger.

public class SyncThread { public static void main(String[] args) { TestThread1 testThread1 = new TestThread1(); TestThread1 testThread4 = new TestThread1(); Thread thread1 = new Thread(testThread1); Thread thread2 = new Thread(testThread4); thread1.start(); thread2.start(); } public static class TestThread1 implements Runnable { private int i = 10; Private void reduce() {synchronized (testthread1.class) {try {String text = string.format ("[thread] : %s print ->%d ", thread.currentThread ().getName(), this.i); System.out.println(text); Thread.sleep(2000); this.i--; } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void run() { reduce(); }}}Copy the code

We replace synchronized (testthread1.class) with synchronized (this) and find that the two rows were printed in about the same time, but revert back and find that the second row was printed 2 seconds later. If other threads access the Reduce method and operate on the TestThread1 type, then multiple threads will execute synchronously.

1.5.3 Other object locks

This is about the same

Test test = new Test();
synchronized (test) {}
Copy the code

Since there is synchronization on methods, can there be synchronization on properties? Watch the next video!

The original address: www.nblogs.cn/doc/java/bd… direct