线程锁synchronized、lock与死锁


在多线程编程中,线程安全是一个关键问题,因为多个线程可能同时访问和修改共享的数据,从而导致不可预测的结果。为了确保线程安全,通常会使用线程同步机制,包括 synchronized 关键字、Lock 接口以及避免死锁的策略。

1. synchronized 关键字

synchronized 是 Java 中用于实现线程同步的关键字。它可以用来修饰方法或代码块。当一个线程进入一个使用 synchronized 修饰的方法或代码块时,其他试图访问相同方法或代码块的线程会被阻塞,直到当前线程执行完毕。这确保了对共享资源的互斥访问。

public class SynchronizedExample {
    private int count = 0;

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

2. Lock 接口

Lock 接口是 Java 中的另一种实现线程同步的机制。相比于 synchronizedLock 提供了更灵活的锁定方式,支持更复杂的线程交互。使用 Lock 的基本模式如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

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

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

3. 死锁

死锁是一种情况,其中两个或多个线程被永久地阻塞,因为它们等待彼此持有的锁。死锁通常发生在多个线程试图获取多个锁的情况下。

避免死锁的一些常见策略包括:

  • 按顺序获取锁:所有线程按照相同的顺序获取锁。
  • 使用 tryLock:在尝试获取锁时设置超时,如果获取不到,释放已经获得的锁。
  • 使用 LocklockInterruptibly:在等待锁的过程中,线程可以被中断。

示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DeadlockExample {
    private Lock lock1 = new ReentrantLock();
    private Lock lock2 = new ReentrantLock();

    public void method1() {
        lock1.lock();
        try {
            // Do something
            lock2.lock();
            try {
                // Do something
            } finally {
                lock2.unlock();
            }
        } finally {
            lock1.unlock();
        }
    }

    public void method2() {
        lock2.lock();
        try {
            // Do something
            lock1.lock();
            try {
                // Do something
            } finally {
                lock1.unlock();
            }
        } finally {
            lock2.unlock();
        }
    }
}

确保线程同步和避免死锁是多线程编程中非常重要的方面。选择使用 synchronized 还是 Lock 取决于具体的需求和场景。


原文链接:codingdict.net