Java并发编程中的锁机制详解

Java并发编程中的锁机制详解

大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!

在Java并发编程中,锁机制是保证线程安全的重要手段。锁的作用是确保同一时刻只有一个线程能够访问被锁保护的资源,从而避免数据不一致和并发冲突。本文将详细介绍Java并发编程中的锁机制,包括内置锁、重入锁、读写锁等,并通过代码示例讲解其使用方法和原理。

1. 内置锁(synchronized)

Java的内置锁是通过synchronized关键字实现的,synchronized可以用来修饰方法或者代码块,确保同一时刻只有一个线程能够执行被synchronized保护的代码。

package cn.juwatech.lock;

public class SynchronizedDemo {
    private int count = 0;

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

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedDemo demo = new SynchronizedDemo();

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

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

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

        t1.join();
        t2.join();

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

在上述代码中,increment方法被synchronized修饰,保证了count变量的自增操作是线程安全的。

2. 重入锁(ReentrantLock)

ReentrantLock是Java并发包中的可重入锁,它提供了比synchronized更灵活的锁机制。例如,ReentrantLock可以实现公平锁、非阻塞地获取锁等功能。

package cn.juwatech.lock;

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

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

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

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo demo = new ReentrantLockDemo();

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

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

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

        t1.join();
        t2.join();

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

上述代码中,increment方法使用ReentrantLock进行加锁和解锁,确保count变量的自增操作是线程安全的。

3. 读写锁(ReadWriteLock)

ReadWriteLock是另一种常用的锁机制,它允许多个读线程并发地访问,但写线程是独占的。这在读多写少的场景中可以显著提高并发性能。

package cn.juwatech.lock;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
    private int count = 0;
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();

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

    public int getCount() {
        rwLock.readLock().lock();
        try {
            return count;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReadWriteLockDemo demo = new ReadWriteLockDemo();

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

        Runnable readTask = () -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("Count: " + demo.getCount());
            }
        };

        Thread t1 = new Thread(writeTask);
        Thread t2 = new Thread(readTask);
        Thread t3 = new Thread(readTask);

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

        t1.join();
        t2.join();
        t3.join();

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

在上述代码中,increment方法使用写锁进行加锁,getCount方法使用读锁进行加锁,确保读写操作的线程安全。

4. 锁的条件变量

ReentrantLock还提供了条件变量(Condition),可以实现更复杂的线程同步控制。通过Condition对象,可以让线程在某个条件下等待,直到条件满足后再继续执行。

package cn.juwatech.lock;

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

public class ConditionDemo {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private boolean ready = false;

    public void waitForCondition() {
        lock.lock();
        try {
            while (!ready) {
                condition.await();
            }
            System.out.println("Condition met, proceeding...");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public void signalCondition() {
        lock.lock();
        try {
            ready = true;
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ConditionDemo demo = new ConditionDemo();

        Runnable waitingTask = demo::waitForCondition;
        Runnable signalingTask = demo::signalCondition;

        Thread t1 = new Thread(waitingTask);
        Thread t2 = new Thread(signalingTask);

        t1.start();
        Thread.sleep(1000);
        t2.start();

        t1.join();
        t2.join();
    }
}

在上述代码中,waitForCondition方法在条件不满足时等待,直到signalCondition方法将条件置为满足并通知所有等待线程。

5. StampedLock

StampedLock是Java 8引入的一种锁机制,它提供了更高效的读写锁,并且支持乐观读操作。StampedLock的主要特点是它使用了戳记(stamp)来控制锁的状态。

package cn.juwatech.lock;

import java.util.concurrent.locks.StampedLock;

public class StampedLockDemo {
    private int count = 0;
    private final StampedLock stampedLock = new StampedLock();

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

    public int getCount() {
        long stamp = stampedLock.tryOptimisticRead();
        int currentCount = count;
        if (!stampedLock.validate(stamp)) {
            stamp = stampedLock.readLock();
            try {
                currentCount = count;
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        return currentCount;
    }

    public static void main(String[] args) throws InterruptedException {
        StampedLockDemo demo = new StampedLockDemo();

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

        Runnable readTask = () -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("Count: " + demo.getCount());
            }
        };

        Thread t1 = new Thread(writeTask);
        Thread t2 = new Thread(readTask);
        Thread t3 = new Thread(readTask);

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

        t1.join();
        t2.join();
        t3.join();

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

在上述代码中,increment方法使用写锁进行加锁,getCount方法尝试使用乐观读锁,如果失败则降级为悲观读锁,确保读写操作的线程安全。

总结

本文详细介绍了Java并发编程中的锁机制,包括内置锁、重入锁、读写锁、条件变量和StampedLock。通过这些示例代码,开发者可以更好地理解和使用Java的各种锁机制,提高并发程序的性能和可靠性。

著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!

posted @ 2024-07-14 15:41  省赚客开发者团队  阅读(2)  评论(0编辑  收藏  举报