Skip to content

08_线程安全实现方法.md

实现线程安全的方法可以归纳为以下几种主要策略:互斥同步、非阻塞同步、线程限制和无同步方案。每种策略都有其适用场景和具体实现方式。下面详细介绍每种策略及其示例代码。

  1. 互斥同步(Mutual Exclusion Synchronization)
  • 互斥同步通过锁(如 synchronized 和 ReentrantLock)来确保同一时刻只有一个线程可以访问共享资源,从而避免数据竞争。
java
public class SynchronizedExample {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}
  1. 非阻塞同步(Non-blocking Synchronization)
  • 非阻塞同步通过原子操作和 CAS(Compare-And-Swap)技术来实现线程安全,避免了线程阻塞。Java 提供了 java.util.concurrent.atomic 包来支持非阻塞同步。
java
import java.util.concurrent.atomic.AtomicInteger;

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

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

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

    public static void main(String[] args) {
        AtomicExample example = new AtomicExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

在这个例子中,AtomicInteger 提供了原子操作 incrementAndGet,确保了 count 变量的线程安全。 3. 线程限制(Thread Confinement)

  • 线程限制通过将数据限制在单个线程中访问,避免了共享数据的并发访问问题。线程限制是最简单的线程安全策略,因为它完全避免了多线程访问共享资源。
java
public class ThreadConfinementExample {

    public static void main(String[] args) {
        Runnable task = () -> {
            int count = 0; // 局部变量,线程限制
            for (int i = 0; i < 1000; i++) {
                count++;
            }
            System.out.println("Final count: " + count);
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,count 变量是局部变量,只能被各自的线程访问,因此不存在并发访问问题。

  1. 无同步方案(No Synchronization)
  • 无同步方案通过使用不可变对象(immutable objects)或将数据分发到各个线程中,避免了同步需求。常见的方式有使用不可变类和线程本地存储(Thread Local Storage)。
java
public final class ImmutableExample {
    private final int count;

    public ImmutableExample(int count) {
        this.count = count;
    }

    public ImmutableExample increment() {
        return new ImmutableExample(this.count + 1);
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        ImmutableExample example = new ImmutableExample(0);

        ImmutableExample newExample = example.increment();
        System.out.println("Original count: " + example.getCount());
        System.out.println("New count: " + newExample.getCount());
    }
}

在这个例子中,ThreadLocal 确保每个线程都有独立的 count 变量实例,避免了并发访问问题。

总结

  • 互斥同步:通过锁机制(如 synchronized 和 ReentrantLock)确保线程对共享资源的互斥访问。
  • 非阻塞同步:通过原子操作和 CAS 技术实现线程安全,避免线程阻塞。
  • 线程限制:通过将数据限制在单个线程中访问,避免了共享数据的并发访问问题。
  • 无同步方案:通过使用不可变对象或线程本地存储,避免了同步需求。