SoFunction
Updated on 2025-04-09

Thread safety in Java and its implementation method

1. What is thread safety?

Thread safety refers to the fact that when multiple threads access a shared resource at the same time, the behavior of the program is still correct. Specifically, thread-safe code can correctly handle access to shared resources in a multi-threaded environment, and there will be no problems such as data competition, deadlocks, and live locks.

1.1 Examples of thread insecure

Here is a simple example of thread insecure:

public class Counter {
    private int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

In this example,increment()MethodscountThe variables are automatically increased. If multiple threads call at the same timeincrement()Methods may causecountThe value of the incorrect one. This is becausecount++An operation is not an atomic operation. It actually includes three steps: reading, modifying and writing. Multiple threads may read the same value at the same time, resulting in incorrect results.

2. How to achieve thread safety?

In Java, there are many ways to achieve thread safety. Here are several common methods.

2.1 Using synchronized keywords

synchronizedKeywords can be used to modify methods or code blocks to ensure that only one thread can execute the modified code at the same time. This can avoid data competition problems caused by multiple threads accessing shared resources simultaneously.

2.1.1 Modification method

public class Counter {
    private int count = 0;

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

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

In this example,increment()andgetCount()All methods aresynchronizedModification ensures that only one thread can execute these methods at the same time.

2.1.2 Modify code blocks

public class Counter {
    private int count = 0;
    private final Object lock = new Object();

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

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

In this example, synchronized modifies a code block and uses a lock object as the lock. This allows for more fine-grained control of the synchronization range and reduces competition for locks.

2.2 Using ReentrantLock

ReentrantLock is a reentrant lock introduced by Java 5, which provides a more flexible lock mechanism than synchronized. ReentrantLock allows more complex lock operations, such as trying to acquire locks, timeout acquisition locks, interruption acquisition locks, etc.

import ;
import ;

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

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

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

In this example, ReentrantLock is used to protect access to the count variable. () and () are used to acquire and release locks, respectively.

2.3 Using Atomic Class

Java provides a series of atomic classes (such as AtomicInteger, AtomicLong, etc.), which achieve lock-free thread safety through CAS (Compare-And-Swap) operations.

import ;

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

    public void increment() {
        ();
    }

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

In this example, AtomicInteger's incrementAndGet() method is an atomic operation that ensures that the value of count is correct in a multithreaded environment.

2.4 Using the volatile keyword

The volatile keyword is used to modify variables to ensure the visibility of the variables. When one thread modifies the value of the volatile variable, other threads can see the modification immediately. However, volatile does not guarantee atomicity, so it is often used for simple state flags.

public class Counter {
    private volatile int count = 0;

    public void increment() {
        count++;  // There are still thread safety issues here    }

    public int getCount() {
        return count;
    }
}

In this example, the count variable is modified by volatile, ensuring visibility, but the increment() method still has thread safety issues because count++ is not an atomic operation.

2.5 Using thread-safe collection classes

Java provides some thread-safe collection classes, such as ConcurrentHashMap, CopyOnWriteArrayList, etc. These collection classes implement thread-safe mechanisms internally and can be used directly in a multi-threaded environment.

import ;

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

    public void add(String key, int value) {
        (key, value);
    }

    public int get(String key) {
        return (key, 0);
    }
}

In this example,ConcurrentHashMapIt is a thread-safe collection class that can be used directly in a multi-threaded environment.

3. Summary

Thread safety is an important concept in multithreading programming, ensuring that the behavior of a program is still correct when multiple threads access shared resources at the same time. In Java, thread safety can be achieved through synchronized keywords, ReentrantLock, Atomic class, volatile keywords, and thread-safe collection classes. The choice of the right method depends on the specific application scenario and performance requirements.

In actual development, understanding the concept of thread safety and using these tools correctly can help us write efficient and reliable multi-threaded programs.

This is the end of this article about thread safety and implementation methods in Java. For more related Java thread safety content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!