java synchronized 保护线程安全

前言

工作中自己实现了一个MySessionContext类,在实现addSession方法的时候,考虑到会有线程不安全问题,这里需要使用synchronized关键字来保护线程安全。


理解 synchronized 关键字需要了解多线程和线程安全的基本概念。在多线程环境中,多个线程可以同时访问共享资源(例如内存中的变量或对象)。如果这些访问没有正确同步,就可能导致数据不一致和其他问题。

多线程与线程安全

多线程:在一个程序中同时运行多个线程,每个线程执行不同的任务。
线程安全:指多个线程访问共享资源时,保证资源的完整性和一致性。

线程不安全问题

假设有一个共享资源 sessionMap(一个 Map<String, HttpSession> 对象),多个线程同时向这个 Map 添加会话对象。如果没有同步机制,可能会出现以下问题:

  1. 数据不一致:多个线程同时写入 sessionMap,可能导致某些写操作丢失或覆盖其他写操作。
  2. 竞争条件:多个线程竞争访问同一个资源,导致程序行为不可预测。
  3. 空指针异常:如果一个线程在另一个线程完成写入之前读取数据,可能会得到不完整或错误的数据。

synchronized 关键字

Synchronized 关键字提供了一种机制,确保在同一时刻只有一个线程可以执行同步代码块,从而避免上述问题。

例子:线程不安全的代码

public void addSession(HttpSession session) {
    if (session != null) {
        sessionMap.put(session.getId(), session);
    }
}

在这个例子中,如果多个线程同时调用 addSession 方法,可能会同时执行 sessionMap.put() 操作,导致数据不一致。

例子:使用 synchronized 关键字确保线程安全

public synchronized void addSession(HttpSession session) {
    if (session != null) {
        sessionMap.put(session.getId(), session);
    }
}

使用 synchronized 关键字可以确保同一时间只有一个线程可以执行 addSession 方法,避免竞争条件和数据不一致的问题。

详细解释 synchronized 的作用

同步方法:在方法定义上使用 synchronized 关键字,如 public synchronized void addSession(HttpSession session),确保同一时间只有一个线程可以执行这个方法。

同步块:你也可以使用同步块来保护共享资源。

public void addSession(HttpSession session) {
    if (session != null) {
        synchronized(this) {
            sessionMap.put(session.getId(), session);
        }
    }
}

synchronized 的执行机制

当一个线程进入 synchronized 方法或同步块时,它会获得该方法或块对应对象的锁(monitor)。
其他线程必须等待,直到当前线程释放锁之后,才能进入该同步方法或同步块。
这样可以确保同一时间只有一个线程访问被保护的代码块,从而保证线程安全。

小结

使用 synchronized 关键字,可以确保同一时刻只有一个线程执行特定的方法或代码块。这种机制通过锁(monitor)来实现,防止多个线程同时访问共享资源,从而避免数据不一致和其他线程安全问题。

补充:
synchronized 和 ReentrantLock (Lock)区别

posted @ 2024-06-21 12:11  r涤生  阅读(28)  评论(0编辑  收藏  举报