# Java并发编程之锁机制

# 1. synchronized 关键字

synchronized是Java提供的最简单、最常用的锁机制。它可以用来同步方法或同步代码块,确保同一时间只有一个线程能访问指定资源。

# 示例:

public class Counter {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 特点:

  • 锁对象:方法上使用this作为锁对象,静态方法使用类的Class对象作为锁。
  • 自动释放:当线程离开同步代码块或方法时,自动释放锁。
  • 性能较低:由于每个进入同步块的线程都需要获取锁,可能导致性能瓶颈。

# 2. ReentrantLock

ReentrantLockjava.util.concurrent.locks包下的锁实现,功能比synchronized更丰富。它支持公平锁、可中断锁、尝试锁等功能。

# 示例:

import java.util.concurrent.locks.ReentrantLock;

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

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

    public int getCount() {
        return count;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 特点:

  • 手动加锁和解锁:使用lock()unlock()进行加锁和解锁,确保在finally中释放锁,避免死锁。
  • 公平锁:可以通过构造函数指定公平性,使等待时间最长的线程优先获取锁。
ReentrantLock lock = new ReentrantLock(true); // 公平锁
1

# 3. ReadWriteLock

ReadWriteLock通过读写分离来提高性能。多个线程可以同时读,但只有一个线程可以写,读写是互斥的。

# 示例:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteCounter {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private int count = 0;

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

    public int getCount() {
        lock.readLock().lock();
        try {
            return count;
        } finally {
            lock.readLock().unlock();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 特点:

  • 读锁可以允许多个线程同时读取数据。
  • 写锁只能允许一个线程修改数据。

# 4. StampedLock

StampedLock是Java 8引入的一种改进的锁机制。相比ReadWriteLock,它更灵活,支持乐观读锁,以提高并发性能。

# 示例:

import java.util.concurrent.locks.StampedLock;

public class StampedCounter {
    private final StampedLock lock = new StampedLock();
    private int count = 0;

    public void increment() {
        long stamp = lock.writeLock();
        try {
            count++;
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    public int getCount() {
        long stamp = lock.tryOptimisticRead();
        int currentCount = count;
        if (!lock.validate(stamp)) {
            stamp = lock.readLock();
            try {
                currentCount = count;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return currentCount;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 特点:

  • 乐观读锁:减少锁的开销,可以允许无锁读取操作。
  • 如果读锁读取期间没有写操作发生,性能会大幅提升。

# 5. Condition

Condition配合ReentrantLock使用,用于线程间通信。它允许线程在等待某个条件时释放锁,直到条件满足后再重新获取锁。

# 示例:

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

public class BoundedBuffer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items = new Object[100];
    private int putIndex, takeIndex, count;

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) {
                notFull.await();
            }
            items[putIndex] = x;
            if (++putIndex == items.length) putIndex = 0;
            count++;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            Object x = items[takeIndex];
            if (++takeIndex == items.length) takeIndex = 0;
            count--;
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 特点:

  • await():让线程等待条件满足并释放锁。
  • signal()signalAll():通知一个或多个等待的线程重新获得锁。

# 总结

  • synchronized适用于简单的线程同步。
  • ReentrantLock提供更灵活的锁机制和更好的性能。
  • ReadWriteLock适合读多写少的场景。
  • StampedLock在读操作较多时提供更好的性能。
  • Condition则适用于更加复杂的线程间协作。
最近更新: 9/24/2024, 10:36:04 PM
备案号:粤ICP备2023124211号-1
Copyright © 2023-2024 StarChenTech All Rights Reserved.