Java并发编程中锁的释放

简介: Java并发编程中锁的释放

主动释放锁,是通过什么方法来达到的呢?
如果,我们看过Object类的方法,我们会注意到它有三个奇怪的方法:wait(),notify()和notifyAll()。 它们就是用来释放锁的。
1 线程的状态#
在讲锁的释放前,我们先讲一下线程的三种主要状态:运行、就绪(可运行)、阻塞。当然,除了这个之外,肯定还有初始状态和结束状态,那个就不讨论了。
threestates.png
当我们创建线程之后,还只是进入初始状态,如果我们调用run()方法运行,根本就不会启动新的线程。当调用start()后,可以将线程状态改为可运行状态,然后,由操作系统来决定调用哪个线程。当幸运的被操作系统选中之后,就可以进入真正的运行状态了。当运行当时间片用完,或者调用yield()礼让方法,就会把当前当执行权交出来,进入可运行就绪状态。如果在运行的过程中,有系统IO,如等待输入,弹出确认对话框等,则会使当前线程进入阻塞状态,动弹不得。只有等待用户操作之后,才能往下进行。sleep()方法和join()方法可以可以达到类似的阻塞效果。
morestates.png
然后,我们把对象锁部分的状态也加进来。当我们使用synchronized修饰方法或者代码块时,会获取对象的锁,并进入获取该对象锁的等待池,由操作系统来决定调用哪个线程(非公平锁)。当获取到该对象锁之后,就可以进入可运行状态了。
另外,还有一个对象的wait()方法,可以使线程放弃持有的该对象锁,并进入通知等待状态。当其他线程调用等待线程需要的对象的notify()或者notifyAll()方法时,该线程重新进入获取对象锁的队列中参与锁的获取。
2 wait() notify() 和 notifyAll()#
synchronized获取锁的方法我们已经详细的讲解过了,我们接下来来看一下如何主动释放锁。假设,我们想创建两个线程,让这两个线程,依次做一件事情,而不是同时启动之后,就由操作系统来决定它们的执行顺序,那么,我们该怎么做呢?
那就是首先请求前一个线程的锁,然后,获取自己线程的锁,再释放自己的锁,并通知这个锁对象的等待队列(下一个线程!哎哎,醒醒别睡啦,起来干活啦!),释放前一个线程的锁,并进入等待前一个锁对象的通知队列。
twothreads.png
用代码展示为:
public class SyncDemo implements Runnable {
private String name;
private Object prev;
private Object cur;

public SyncDemo(String name, Object prev, Object cur) {
    this.name = name;
    this.prev = prev;
    this.cur = cur;
}

@Override
public void run() {
    int count = 10;
    while (count > 0) {
        synchronized(prev) {
            synchronized(cur) {
                System.out.println(name);
                count--;
                cur.notify();
            }
            try {
                prev.wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

public static void main(String[] args) {
    Object a = new Object();
    Object b = new Object();
    SyncDemo r1 = new SyncDemo("A", b, a);
    SyncDemo r2 = new SyncDemo("B", a, b);

    new Thread(r1).start();
    try {
        Thread.sleep(100);
    } catch (Exception e) {
        e.printStackTrace();
    }
    new Thread(r2).start();
}

}
//代码效果参考:http://www.zidongmutanji.com/zsjx/31939.html

写得更通用一点,支持更多的线程依次执行:
public static void main(String[] args) {
int num = 5;

Object[] locks = new Object[num];
String[] names = {"A", "B", "C", "D", "E"};
SyncDemo[] runnable = new SyncDemo[num];

for (int i = 0; i < num; i++) {
    locks[i] = new Object();
}

for (int i = 0; i < num; i++) {
    runnable[i] = new SyncDemo(names[i], locks[(i - 1 + num) % num] , locks[i]);
}

for (int i = 0; i < num; i++) {
    new Thread(runnable[i]).start();
    try {
        Thread.sleep(100);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

}

相关文章
|
13天前
|
安全 Java 程序员
深入理解Java内存模型与并发编程####
本文旨在探讨Java内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
20 0
|
15天前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
18天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
18天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
12天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
12天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
34 3
|
18天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
60 6
|
17天前
|
开发框架 安全 Java
Java 反射机制:动态编程的强大利器
Java反射机制允许程序在运行时检查类、接口、字段和方法的信息,并能操作对象。它提供了一种动态编程的方式,使得代码更加灵活,能够适应未知的或变化的需求,是开发框架和库的重要工具。
35 2
|
18天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
52 1
|
19天前
|
Java API 数据库
Java 反射机制:动态编程的 “魔法钥匙”
Java反射机制是允许程序在运行时访问类、方法和字段信息的强大工具,被誉为动态编程的“魔法钥匙”。通过反射,开发者可以创建更加灵活、可扩展的应用程序。
36 0