Java中Lock锁基本使用方法详解

 更新时间:2023年11月21日 11:21:55   作者:Jay/.  
锁是一种工具,用于控制对共享资源的访问Lock和synchronized是最常见的两个锁,他们都能够达到线程安全的目录,这篇文章主要给大家介绍了关于Java中Lock锁基本使用方法详解的相关资料,需要的朋友可以参考下

一、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锁详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 中使用maven shade plugin 打可执行Jar包

    java 中使用maven shade plugin 打可执行Jar包

    这篇文章主要介绍了java 中使用maven shade plugin 打可执行Jar包的相关资料,需要的朋友可以参考下
    2017-05-05
  • java使用Abobe Acrobat DC生成模板

    java使用Abobe Acrobat DC生成模板

    这篇文章主要介绍了java使用Abobe Acrobat DC生成模板,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Java之IO流面试题案例讲解

    Java之IO流面试题案例讲解

    这篇文章主要介绍了Java之IO流案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • SpringData JPA的常用语法汇总

    SpringData JPA的常用语法汇总

    Spring Data JPA是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作,下面这篇文章主要给大家介绍了关于SpringData JPA的常用语法,需要的朋友可以参考下
    2022-06-06
  • java如何解析/读取xml文件

    java如何解析/读取xml文件

    这篇文章主要为大家详细介绍了java如何解析/读取xml文件的方法,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • java:java.lang.ExceptionInInitializerError报错解决过程

    java:java.lang.ExceptionInInitializerError报错解决过程

    这篇文章主要给大家介绍了关于java:java.lang.ExceptionInInitializerError报错的解决过程,java.lang.ExceptionInInitializerError 是一个异常,表示在初始化一个类的静态变量或静态块时发生了错误,需要的朋友可以参考下
    2023-10-10
  • Java实现高效PDF文件传输技巧

    Java实现高效PDF文件传输技巧

    你是否曾为PDF文件传输的低效率而苦恼?现在,有了这份Java实现高效PDF文件传输技巧指南,你将能够轻松解决这个问题,我们将分享一些实用的技巧和最佳实践,帮助你优化文件传输过程,不要错过这个提高工作效率的机会,快来阅读这份指南吧!
    2024-03-03
  • Springboot使用@Cacheable注解实现数据缓存

    Springboot使用@Cacheable注解实现数据缓存

    本文介绍如何在Springboot中通过@Cacheable注解实现数据缓存,在每次调用添加了@Cacheable注解的方法时,Spring 会检查指定参数的指定目标方法是否已经被调用过,文中有详细的代码示例,需要的朋友可以参考下
    2023-10-10
  • Spring Data JPA进行数据分页与排序的方法

    Spring Data JPA进行数据分页与排序的方法

    这篇文章主要介绍了Spring Data JPA进行数据分页与排序的方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • Java中的static--静态变量你了解吗

    Java中的static--静态变量你了解吗

    Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问,.下面我们来详细了解一下吧
    2021-09-09

最新评论