java系列-锁分为哪几类

在 Java 多线程编程中,锁机制是一种重要的同步工具,用于协调线程之间的访问和操作。Java 中的锁可以分为几类,主要包括:

1. 互斥锁(Mutex)

  • 互斥锁是最常见的一种锁,用于保护共享资源,确保同一时刻只有一个线程可以访问这个资源。
  • Java 中的 `synchronized` 关键字就是一种互斥锁机制,通过对代码块或方法进行同步,确保在同一时刻只有一个线程可以执行。
class SharedResource {
    private int count = 0;

    // 使用 synchronized 关键字创建互斥锁
    public synchronized void increment() {
        count++;
    }

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

class MyThread extends Thread {
    private SharedResource sharedResource;

    public MyThread(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }

    @Override
    public void run() {
        // 在互斥锁的保护下对共享资源进行操作
        for (int i = 0; i < 10000; i++) {
            sharedResource.increment();
        }
    }
}

public class MutexLockExample {
    public static void main(String[] args) throws InterruptedException {
        SharedResource sharedResource = new SharedResource();

        // 创建两个线程共享同一个对象
        Thread thread1 = new MyThread(sharedResource);
        Thread thread2 = new MyThread(sharedResource);

        // 启动线程
        thread1.start();
        thread2.start();

        // 等待两个线程执行完成
        thread1.join();
        thread2.join();

        // 输出最终的共享资源的值
        System.out.println("Final Count: " + sharedResource.getCount());
    }
}

2. 可重入锁(Reentrant Lock)

  • 可重入锁是一种允许同一个线程多次获得同一把锁的锁机制。如果一个线程已经获得了锁,它可以再次获取相同的锁而不被阻塞。
  • Java 中的 `ReentrantLock` 类提供了可重入锁的实现。
import java.util.concurrent.locks.ReentrantLock;

class SharedResource {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void performTask() {
        lock.lock(); // 获取锁
        try {
            // 可重入锁允许在持有锁的情况下再次获取锁
            anotherTask();
            count++;
            System.out.println(Thread.currentThread().getName() + ": Count is " + count);
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    private void anotherTask() {
        lock.lock(); // 在同一个线程中再次获取锁
        try {
            count++;
            System.out.println(Thread.currentThread().getName() + ": Another Task, Count is " + count);
        } finally {
            lock.unlock(); // 释放锁
        }
    }
}

class MyThread extends Thread {
    private SharedResource sharedResource;

    public MyThread(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }

    @Override
    public void run() {
        sharedResource.performTask();
    }
}

public class ReentrantLockExample {
    public static void main(String[] args) {
        SharedResource sharedResource = new SharedResource();

        // 创建两个线程共享同一个对象
        Thread thread1 = new MyThread(sharedResource);
        Thread thread2 = new MyThread(sharedResource);

        // 启动线程
        thread1.start();
        thread2.start();
    }
}

3. 读写锁(Read/Write Lock)

  • 读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这样可以提高读操作的并发性。
  • Java 中的 `ReentrantReadWriteLock` 类提供了读写锁的实现。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWriteLockExample {

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private int sharedData = 0;

    public int readData() {
        readWriteLock.readLock().lock(); // 获取读锁
        try {
            System.out.println(Thread.currentThread().getName() + " is reading data: " + sharedData);
            return sharedData;
        } finally {
            readWriteLock.readLock().unlock(); // 释放读锁
        }
    }

    public void writeData(int newValue) {
        readWriteLock.writeLock().lock(); // 获取写锁
        try {
            System.out.println(Thread.currentThread().getName() + " is writing data: " + newValue);
            sharedData = newValue;
        } finally {
            readWriteLock.writeLock().unlock(); // 释放写锁
        }
    }

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

        // 创建并启动多个读线程和一个写线程
        for (int i = 0; i < 5; i++) {
            new ReaderThread(example).start();
        }

        new WriterThread(example, 100).start();
    }

    static class ReaderThread extends Thread {
        private final ReentrantReadWriteLockExample example;

        public ReaderThread(ReentrantReadWriteLockExample example) {
            this.example = example;
        }

        @Override
        public void run() {
            example.readData();
        }
    }

    static class WriterThread extends Thread {
        private final ReentrantReadWriteLockExample example;
        private final int newValue;

        public WriterThread(ReentrantReadWriteLockExample example, int newValue) {
            this.example = example;
            this.newValue = newValue;
        }

        @Override
        public void run() {
            example.writeData(newValue);
        }
    }
}

4. 悲观锁和乐观锁

  • 悲观锁认为在整个过程中都会发生冲突,因此在访问共享资源前会先加锁。`synchronized` 和 `ReentrantLock` 就是悲观锁的实现。
  • 乐观锁则认为冲突是少数情况,它不会在访问共享资源前加锁,而是在更新时检查是否有其他线程修改了数据。常见的实现方式包括无锁编程、CAS(Compare and Swap)等。

5. 自旋锁

  • 自旋锁是一种在获取锁失败时,线程不会立即被阻塞,而是采用循环方式不断尝试获取锁的锁机制。适用于锁占用时间很短暂的情况。
  • Java 中的 `java.util.concurrent.atomic` 包中的原子类使用了类似的自旋锁的概念。
import java.util.concurrent.atomic.AtomicInteger;

public class SpinLockExample {

    private AtomicInteger lock = new AtomicInteger(0);

    public void lock() {
        while (!tryLock()) {
            // 自旋等待锁
        }
    }

    public void unlock() {
        lock.set(0);
    }

    private boolean tryLock() {
        return lock.compareAndSet(0, 1);
    }

    public static void main(String[] args) {
        SpinLockExample spinLockExample = new SpinLockExample();

        // 创建并启动两个线程
        new WorkerThread(spinLockExample, "Thread-1").start();
        new WorkerThread(spinLockExample, "Thread-2").start();
    }

    static class WorkerThread extends Thread {
        private final SpinLockExample spinLockExample;

        public WorkerThread(SpinLockExample spinLockExample, String name) {
            super(name);
            this.spinLockExample = spinLockExample;
        }

        @Override
        public void run() {
            spinLockExample.lock();
            try {
                System.out.println(getName() + " is working");
                // 模拟工作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                spinLockExample.unlock();
                System.out.println(getName() + " is done working");
            }
        }
    }
}

6. 公平锁和非公平锁

  • 锁会按照线程请求锁的顺序来分配锁,而非公平锁则不考虑线程请求锁的顺序,有可能导致某些线程一直获取不到锁。
  • `ReentrantLock` 可以通过构造函数指定是公平锁还是非公平锁。

7. 条件锁(Condition)

  • 条件锁是一种支持线程之间按照条件等待和通知的锁机制。它通常与可重入锁一起使用。

  • Java 中的 `ReentrantLock` 类提供了 `newCondition` 方法用于创建条件锁。

这些锁机制在不同的场景下有各自的优缺点,选择合适的锁对于多线程程序的性能和正确性都有着重要的影响。

(记不住呀/(ㄒoㄒ)/~~,老是忘记,搞混)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值