Java中Lock锁基本使用方法详解
作者:Jay/.
一、Lock锁的基本使用
在Java中,Lock是一个接口,它提供了比synchronized关键字更高级的线程同步机制。使用Lock接口可以创建更复杂和灵活的同步结构。
Lock接口的常用实现类有ReentrantLock和ReentrantReadWriteLock,它们提供了可重入的互斥锁和读写锁。
使用Lock锁的一般步骤如下:
1. 创建一个`Lock`对象实例。
Lock lock = new ReentrantLock();
2. 在需要进行同步的代码块中,通过调用`lock()`方法来获取锁。
lock.lock(); try { // 同步的代码 } finally { // 在finally块中释放锁,以确保锁的释放 lock.unlock(); }
3. 在同步的代码块执行完之后,通过调用`unlock()`方法释放锁。示例代码:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { private static Lock lock = new ReentrantLock(); public static void main(String[] args) { Thread t1 = new Thread(() -> { acquireLock(); }); Thread t2 = new Thread(() -> { acquireLock(); }); t1.start(); t2.start(); } private static void acquireLock() { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " 获取到了锁"); // 执行同步的代码块 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println(Thread.currentThread().getName() + " 释放了锁"); lock.unlock(); // 释放锁 } } } ``` 输出: ``` Thread-0 获取到了锁 Thread-0 释放了锁 Thread-1 获取到了锁 Thread-1 释放了锁 ```
在上述示例中,我们创建了一个ReentrantLock实例作为锁对象。然后,我们创建两个线程t1和t2,它们都会调用acquireLock()方法获取锁并执行同步的代码块。最后,我们可以看到两个线程交替地获取到锁、执行同步代码块并释放锁。
需要注意的是,在使用Lock接口时要注意在finally块中释放锁,以确保在任何情况下都能正常释放锁。否则可能会导致线程出现死锁的情况。
使用Lock锁可以灵活控制线程的同步和互斥,并提供了更多的高级功能,例如可中断的锁、条件变量等,可以更好地实现复杂的并发控制需求。
二、Condition类详解
在Java中,Condition类是Java.util.concurrent包下的一个接口,用于支持线程的等待和通知机制。它通常与Lock接口一起使用,用于实现线程间的同步和协调。
Condition类提供了以下方法:
1. await():使当前线程等待,直到被其他线程调用signal()或signalAll()方法唤醒。
2. awaitUninterruptibly():类似于await()方法,但是在等待期间不会响应线程中断。
3. await(long time, TimeUnit unit):使当前线程等待一段时间,在指定的时间内没有被其他线程调用signal()或signalAll()方法唤醒,将自动唤醒。
4. awaitNanos(long nanosTimeout):使当前线程等待一段纳秒时间,在指定的时间内没有被其他线程调用signal()或signalAll()方法唤醒,将自动唤醒。
5. awaitUntil(Date deadline):使当前线程等待直到某个时间,如果在指定时间内没有被其他线程调用signal()或signalAll()方法唤醒,将自动唤醒。
6. signal():唤醒一个等待在Condition上的线程,并使其从await()方法返回。
7. signalAll():唤醒所有等待在Condition上的线程,并使它们从await()方法返回。使用示例:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConditionExample { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public void doSomething() { lock.lock(); try { // 等待条件 condition.await(); // 执行其他操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void notifyThread() { lock.lock(); try { // 唤醒线程 condition.signal(); } finally { lock.unlock(); } } }
在上述示例中,使用lock对象创建了一个Condition实例condition。在doSomething()方法中,线程将调用condition.await()进入等待状态,直到其他线程调用condition.signal()方法唤醒它。notifyThread()方法用于唤醒等待在condition上的线程。
这样,通过Condition类的使用,我们可以实现线程之间的等待和通知机制,实现更灵活的线程同步与协调。
三、进程的优先级
在Java中,可以使用Thread类的setPriority(int priority)方法来设置线程的优先级。Java中的线程优先级范围是1(最低优先级)到10(最高优先级),其中5为默认优先级。
一个线程的优先级仅仅是给调度器一个提示,告诉它该如何调度线程,实际上是由操作系统来决定如何处理线程的优先级。不同操作系统可能会有不同的处理方式,且并不能保证线程优先级会完全按照设定的顺序高低执行。
以下是设置线程优先级的示例代码:
package lzx6; public class ThreadPriorityExample { public static void main(String[] args) { Thread thread1 = new Thread(() -> { for (int i = 0;; i++) { System.out.println("Thread 1: " + i); } }); Thread thread2 = new Thread(() -> { for (int i = 0;;i++ ) { System.out.println("Thread 2: " + i); } }); // 设置线程的优先级 thread1.setPriority(Thread.MIN_PRIORITY); // 最低优先级 thread2.setPriority(Thread.MAX_PRIORITY); // 最高优先级 // 启动线程 thread1.start(); thread2.start(); } }
运行结果:
可以看到确实进程2的优先级更高。
在上述代码中,我们创建了两个线程thread1和thread2,分别输出各自线程标识和循环变量的值。我们通过调用thread1.setPriority(Thread.MIN_PRIORITY)设置thread1线程为最低优先级,通过调用thread2.setPriority(Thread.MAX_PRIORITY)设置`thread2`线程为最高优先级。
需要注意的是,线程的优先级只是给调度器提供了一个提示,不同的操作系统可能有不同的实现方式,而且不能保证线程会按照设定的优先级顺序执行。此外,线程优先级的相对差异通常只在较忙碌的系统中才能明显体现出来,在负载较轻的系统中可能不会有明显的效果。Oracle提供的Linux的Java虚拟机中,线程优先级都是一样的。
四、wait/join与sleep的区别:
wait(), join(), 和 sleep() 是用于控制线程执行的方法,它们在用途和行为上有一些区别。
1. wait(): 是Object类的方法,用于使当前线程进入等待状态,直到其他线程调用相同对象上的notify()或notifyAll()方法来唤醒等待的线程。wait()方法必须在同步代码块或同步方法中调用。
2. join(): 是Thread类的方法,用于等待调用join()方法的线程执行完毕。当一个线程调用其他线程的join()方法时,当前线程会进入等待状态,直到被调用的线程执行完毕。join()方法通常用于多线程协作,以确保线程执行的顺序。
3. sleep(): 是Thread类的方法,用于使当前线程进入休眠状态(阻塞),暂时中止执行一段时间。sleep()方法会让线程暂停执行指定的时间,然后重新进入可运行状态。
关键区别如下:
- - wait()和join()方法都依赖于其他线程的操作,而`sleep()方法是通过指定的时间来控制线程执行。
- - wait()方法在等待期间会释放对象的锁,而sleep()方法和join()方法在等待期间仍然持有对象的锁。
- - wait()方法必须在同步代码块或同步方法中调用,而sleep()方法和join()方法可以在任何地方调用。
- - wait()方法需要被唤醒后才能继续执行,而sleep()方法和join()方法可以在指定的时间过去后自动继续执行。
总结来说,wait()方法和join()方法是用于线程间的通信和协作,sleep()方法是用于控制线程执行时间的暂停。
总结
到此这篇关于Java中Lock锁基本使用方法详解的文章就介绍到这了,更多相关Java Lock锁详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!