Java Lock 线程同步实现(java线程同步的几种方法)

在 Java 中,除了使用 synchronized 关键字实现线程同步外,还可以使用
java.util.concurrent.locks.Lock
接口及其实现类(如 ReentrantLock)来实现更灵活的线程同步。Lock 提供了比 synchronized 更强大的功能,例如可重入锁、公平锁、尝试获取锁、超时获取锁等。


1.Lock 的基本使用

Lock 是一个接口,常用的实现类是 ReentrantLock。以下是 Lock 的基本用法:

示例:使用ReentrantLock实现线程同步

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

public class LockDemo {
    private static int counter = 0;
    private static final Lock lock = new ReentrantLock(); // 创建锁对象

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                lock.lock(); // 加锁
                try {
                    counter++; // 操作共享资源
                } finally {
                    lock.unlock(); // 释放锁
                }
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
        System.out.println("Counter: " + counter); // 输出 2000
    }
}

2.Lock 的特点

  • o 显式锁:需要手动加锁和释放锁。
  • o 可重入锁:同一个线程可以多次获取同一把锁。
  • o 公平锁:支持公平锁和非公平锁(默认是非公平锁)。
  • o 尝试获取锁:可以尝试获取锁,如果锁不可用则立即返回或等待一段时间。
  • o 超时获取锁:可以设置超时时间,避免死锁。

3.尝试获取锁

使用 tryLock() 方法尝试获取锁,如果锁不可用则立即返回 false,避免线程阻塞。

示例:尝试获取锁

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

public class TryLockDemo {
    private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Runnable task = () -> {
            if (lock.tryLock()) { // 尝试获取锁
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取到锁,正在执行任务...");
                    Thread.sleep(1000); // 模拟任务执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock(); // 释放锁
                }
            } else {
                System.out.println(Thread.currentThread().getName() + " 未获取到锁,执行其他操作...");
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();
    }
}

4.超时获取锁

使用 tryLock(long time, TimeUnit unit) 方法在指定时间内尝试获取锁,超时后返回 false

示例:超时获取锁

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

public class TryLockTimeoutDemo {
    private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        Runnable task = () -> {
            try {
                if (lock.tryLock(1, TimeUnit.SECONDS)) { // 尝试在 1 秒内获取锁
                    try {
                        System.out.println(Thread.currentThread().getName() + " 获取到锁,正在执行任务...");
                        Thread.sleep(2000); // 模拟任务执行
                    } finally {
                        lock.unlock(); // 释放锁
                    }
                } else {
                    System.out.println(Thread.currentThread().getName() + " 未获取到锁,放弃执行...");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();
    }
}

5.公平锁

ReentrantLock 支持公平锁和非公平锁。公平锁会按照线程请求锁的顺序分配锁,而非公平锁则允许插队。

示例:公平锁

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

public class FairLockDemo {
    private static final Lock lock = new ReentrantLock(true); // 创建公平锁

    public static void main(String[] args) {
        Runnable task = () -> {
            for (int i = 0; i < 3; i++) {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取到锁,执行任务...");
                    Thread.sleep(100); // 模拟任务执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread thread1 = new Thread(task, "Thread-1");
        Thread thread2 = new Thread(task, "Thread-2");
        Thread thread3 = new Thread(task, "Thread-3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

6.Condition 实现线程通信

Lock 可以与 Condition 结合使用,实现更灵活的线程通信(类似于 wait()notify())。

示例:使用Condition实现生产者-消费者模型

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

public class ProducerConsumerDemo {
    private static final Lock lock = new ReentrantLock();
    private static final Condition notFull = lock.newCondition(); // 条件变量:队列未满
    private static final Condition notEmpty = lock.newCondition(); // 条件变量:队列未空
    private static final int CAPACITY = 10;
    private static final int[] queue = new int[CAPACITY];
    private static int count = 0, putIndex = 0, takeIndex = 0;

    public static void main(String[] args) {
        Runnable producer = () -> {
            for (int i = 0; i < 20; i++) {
                lock.lock();
                try {
                    while (count == CAPACITY) {
                        notFull.await(); // 队列已满,等待
                    }
                    queue[putIndex] = i;
                    putIndex = (putIndex + 1) % CAPACITY;
                    count++;
                    notEmpty.signal(); // 通知消费者
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Runnable consumer = () -> {
            for (int i = 0; i < 20; i++) {
                lock.lock();
                try {
                    while (count == 0) {
                        notEmpty.await(); // 队列为空,等待
                    }
                    int item = queue[takeIndex];
                    takeIndex = (takeIndex + 1) % CAPACITY;
                    count--;
                    notFull.signal(); // 通知生产者
                    System.out.println("消费: " + item);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

总结

  • o Lock 提供了比 synchronized 更灵活的线程同步机制。
  • o 使用 tryLock() 和超时机制可以避免死锁。
  • o Condition 可以实现复杂的线程通信。
  • o 推荐在需要高级功能(如公平锁、尝试获取锁等)时使用 Lock,否则可以使用 synchronized

希望这些示例能帮助你掌握 Java 中 Lock 的使用!

#java 编程##java##线程##lock##并发出现线程不安全的本质什么?##高并发#

原文链接:,转发请注明来源!