[Java] What are the implementation ideas of thread safety in Java?


In Java multithreaded programming, thread safety is a very important concept. Thread safety usually means that a program can still maintain correct behavior when multiple threads are executed concurrently. Java provides many methods to achieve thread safety, this article will introduce several common implementation ideas.
insert image description here

1. Use the synchronized keyword

The synchronized keyword is the most fundamental way to solve the problem of thread safety in Java, which can ensure that the code block is executed atomically. synchronized can be used to decorate instance methods, static methods and code blocks. The following is the sample code of the synchronized modified instance method:

public class Counter {
    
    
    private int count;

    public synchronized void increment() {
    
    
        count++;
    }

    public synchronized int getCount() {
    
    
        return count;
    }
}

In the above code, both the increment() and getCount() methods are modified by synchronized, so that only one thread can access them at a time. Although this method is simple, its efficiency is relatively low, because only one thread can access these methods at a time.

2. Use the ReentrantLock class

The ReentrantLock class in Java provides a more flexible thread synchronization mechanism than synchronized. ReentrantLock is reentrant, can interrupt the thread waiting for the lock, and try to acquire the lock through the tryLock() method. The following is a sample code for thread safety using ReentrantLock:

import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    
    
    private int count;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
    
    
        lock.lock();
        try {
    
    
            count++;
        } finally {
    
    
            lock.unlock();
        }
    }

    public int getCount() {
    
    
        lock.lock();
        try {
    
    
            return count;
        } finally {
    
    
            lock.unlock();
        }
    }
}

In the above code, lock.lock() is used to acquire the lock and lock.unlock() is used to release the lock. When using ReentrantLock, it should be noted that the logic of acquiring and releasing locks must be placed in a try-finally block to ensure that the lock must be released correctly.

3. Use the ConcurrentHashMap class

ConcurrentHashMap is a thread-safe hash table implementation in Java. ConcurrentHashMap uses a segment lock mechanism to divide the entire hash table into multiple segments, and elements in different segments can be accessed by multiple threads at the same time. Here is an example code for thread safety using ConcurrentHashMap:

import java.util.concurrent.ConcurrentHashMap;

public class Counter {
    
    
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

    public void increment(String key) {
    
    
        map.put(key, map.getOrDefault(key, 0) + 1);
    }

    public int getCount(String key) {
    
    
        return map.getOrDefault(key, 0);
    }
}

In the above code, ConcurrentHashMap is used to store the value of the counter, and the method of map.put() and map.getOrDefault() is used to update and get the value of the counter. Since ConcurrentHashMap is thread-safe, this implementation can ensure that the value of the counter is correct when multiple threads access it at the same time.

4. Use the Atomic class

The Atomic class in Java provides a set of atomic operations that ensure operations are performed atomically. Atomic classes include AtomicBoolean, AtomicInteger, AtomicLong, etc. Here is an example code for thread safety using AtomicInteger:

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    
    
    private AtomicInteger count = new AtomicInteger();

    public void increment() {
    
    
        count.incrementAndGet();
    }

    public int getCount() {
    
    
        return count.get();
    }
}

In the above code, AtomicInteger is used to store the value of the counter, and the count.incrementAndGet() method is used to update the value of the counter. Since AtomicInteger is thread-safe, this implementation can ensure that the value of the counter is correct when multiple threads access it at the same time.

5. Use the ThreadLocal class

The ThreadLocal class allows each thread to have its own copy of variables. When multiple threads execute concurrently, each thread can independently operate its own copy of variables, thereby avoiding thread safety issues. The following is sample code for thread safety using ThreadLocal:

public class Counter {
    
    
    private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);

    public void increment() {
    
    
        threadLocal.set(threadLocal.get() + 1);
    }

    public int getCount() {
    
    
        return threadLocal.get();
    }
}

In the above code, the ThreadLocal class is used to store the value of the counter, and the threadLocal.set() and threadLocal.get() methods are used to update and obtain the value of the counter. Since each thread has its own copy of the variable, this implementation ensures that the value of the counter is correct when multiple threads access it at the same time.

Summarize

This article introduces several ways to achieve thread safety in Java, including the synchronized keyword, ReentrantLock class, ConcurrentHashMap class, Atomic class, ThreadLocal class, etc. Each method has its characteristics and applicable scenarios, and the appropriate method needs to be selected according to actual needs. In practical applications, in order to better improve the performance and concurrency of the system, multiple methods can be used in combination to achieve thread safety.

Guess you like

Origin blog.csdn.net/u011397981/article/details/130653239