0. Leading question code
The following code demonstrates a counter. Two threads perform cumulative operations on i at the same time, each executing 1,000,000 times. The result we expect is definitely i=2000000. But After we execute it multiple times, we will find that the value of i is always less than 2000000. This is because when two threads write to i at the same time, the result of one thread will overwrite the other.
public class AccountingSync implements Runnable { static int i = 0; public void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { AccountingSync accountingSync = new AccountingSync(); Thread t1 = new Thread(accountingSync); Thread t2 = new Thread(accountingSync); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
To fundamentally solve this problem, we must ensure that multiple threads are completely synchronized when operating on i. That is to say, when thread A writes to i , B thread cannot not only write, but also cannot read.
1. The role of the synchronized keyword
The function of the synchronized keyword is actually to achieve synchronization between threads . Its job is to lock the synchronized code so that only one thread can enter the synchronized block at a time, thus ensuring the security between threads. Just like in the above code, i++ can only operate on one thread at the same time. During execution.
2. Usage of synchronized keyword
Specify object lock: lock the given object, enter the synchronized code block to obtain the lock of the given object
Acts directly on instance methods: equivalent to locking the current instance. Entering the synchronization code block requires obtaining the lock of the current instance (this requires the same Runnable instance to be used when creating Thread)
Acts directly on static methods: equivalent to locking the current class. Before entering the synchronization code block, you must obtain the lock of the current class.
2.1 Lock the specified object
Below The code applies synchronized to a given object. One thing to note here is that the given object must be static, otherwise every time we create a new thread, the object will not be shared with each other, and the meaning of locking will be meaningless. Exists.
public class AccountingSync implements Runnable { final static Object OBJECT = new Object(); static int i = 0; public void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { synchronized (OBJECT) { increase(); } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AccountingSync()); Thread t2 = new Thread(new AccountingSync()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
2.2 Acts directly on instance methods
synchronized The keyword acts on instance methods, which means that before entering the increase() method, the thread must obtain the lock of the current instance. This requires us to use the same Runnable object instance when creating a Thread instance. Otherwise, the thread's The locks are not on the same instance, so there is no way to talk about locking/synchronization issues.
public class AccountingSync implements Runnable { static int i = 0; public synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { AccountingSync accountingSync = new AccountingSync(); Thread t1 = new Thread(accountingSync); Thread t2 = new Thread(accountingSync); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
Please pay attention to the first three lines of the main method, describing the keywords The correct usage of acting on instance methods.
2.3 Acting directly on static methods
Use the synchronized keyword on static methods, so there is no need to use two The threads must point to the same Runnable method. Because the method block needs to request the lock of the current class, not the current instance, threads can still be synchronized correctly.
public class AccountingSync implements Runnable { static int i = 0; public static synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AccountingSync()); Thread t2 = new Thread(new AccountingSync()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
3. Wrong locking
From the above example, we know that if we need a counter application, in order to ensure the correctness of the data, we will naturally need to lock the counter. Therefore, we may The following code will be written:
public class BadLockOnInteger implements Runnable { static Integer i = 0; @Override public void run() { for (int j = 0; j < 1000000; j++) { synchronized (i) { i++; } } } public static void main(String[] args) throws InterruptedException { BadLockOnInteger badLockOnInteger = new BadLockOnInteger(); Thread t1 = new Thread(badLockOnInteger); Thread t2 = new Thread(badLockOnInteger); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
When we run the above code, we will find that the output i is very small. This shows that the thread is not safe.
To explain this problem, we have to start with Integer: In Java, Integer is an immutable object. Like String, once the object is created, it cannot be modified. If you have an Integer=1, then It will always be 1. What if you want this object = 2? You can only recreate an Integer. After each i++, it is equivalent to calling the valueOf method of Integer. Let's take a look at the source code of the valueOf method of Integer:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
## Integer.valueOf() is actually a factory method. It will tend to return a new Integer object and re-copy the value to i;

This article analyzes the top four JavaScript frameworks (React, Angular, Vue, Svelte) in 2025, comparing their performance, scalability, and future prospects. While all remain dominant due to strong communities and ecosystems, their relative popul

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

This article addresses the CVE-2022-1471 vulnerability in SnakeYAML, a critical flaw allowing remote code execution. It details how upgrading Spring Boot applications to SnakeYAML 1.33 or later mitigates this risk, emphasizing that dependency updat

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa

Node.js 20 significantly enhances performance via V8 engine improvements, notably faster garbage collection and I/O. New features include better WebAssembly support and refined debugging tools, boosting developer productivity and application speed.

Iceberg, an open table format for large analytical datasets, improves data lake performance and scalability. It addresses limitations of Parquet/ORC through internal metadata management, enabling efficient schema evolution, time travel, concurrent w

This article explores integrating functional programming into Java using lambda expressions, Streams API, method references, and Optional. It highlights benefits like improved code readability and maintainability through conciseness and immutability

This article explores methods for sharing data between Cucumber steps, comparing scenario context, global variables, argument passing, and data structures. It emphasizes best practices for maintainability, including concise context use, descriptive


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Linux new version
SublimeText3 Linux latest version

Notepad++7.3.1
Easy-to-use and free code editor

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

Dreamweaver CS6
Visual web development tools
