`
xuyongping
  • 浏览: 123572 次
  • 性别: Icon_minigender_1
  • 来自: 部落格
社区版块
存档分类
最新评论

ReentrantLock 到底锁定了哪个对象了?

 
阅读更多
一个简单的ReentrantLock的例子, 情景是几个朋友吃饭, 可是美味的汤只有一锅, 勺子只有一个. 这样一来, 难免就会有你抢我争的情况了. 但是, 如果有更美味的其他食物, 当然可以先转头去找其他的了. synchronized是无法做到这点的.

Lunch类, 包括勺子(ReentrantLock)和"舀"的动作, 当这帮朋友想要"舀"的时候, 就只能一个人动手, 其他人乖乖等着, 或者被叫去干其他事情
package concurrent.lunch;
import java.util.concurrent.locks.ReentrantLock;

public class Lunch {
    private ReentrantLock scoop = new ReentrantLock();

    public boolean dip() {
        try {
            scoop.lockInterruptibly();
        } catch (InterruptedException e) {
            Logger.log("Some one call me for better food ^^ ");
            return false;
        }

        Logger.log("hah, I got the scoop");
        try {
            // suppose we need 5s to dip the soup
            try {
                Thread.sleep(5000);
            } catch (InterruptedException i) {
                Logger.log("someone rob my scoop, 55~~~ ");
                return false;
            }
            Logger.log("I got delicious food ");
        } finally {
            scoop.unlock();
        }
        return true;
    }
}

Buddy类, 嘴馋的家伙, 抢着要"舀"汤, 不过如果抢不到, 也可以干别的
package concurrent.lunch;
public class Buddy extends Thread {
    private final Lunch lunch;
    public Buddy(Lunch lunch, String name) {
        this.lunch = lunch;
        this.setName(name);
    }
    public void run() {
        while (!lunch.dip()) {
            Logger.log("I will wait for a while to dip, see if any other better...");
            try {
                Thread.sleep(100);
            } catch (InterruptedException ignore) {}
        }
    }
}

Party类, 宴会开始了, 每个人都想去抢那个勺子, 抢不到的又实在等不耐烦的话就只好暴力解决(interrupt)
package concurrent.lunch;
public class Party {
    public static void main(String[] args) throws Exception {
        // here we have to share the Lunch instance
        Lunch lunch = new Lunch();
       
        // here we MUST share the Lunch instance
        Buddy Tityz= new Buddy(lunch, "Tityz");
        Buddy Michael = new Buddy(lunch, "Michael");
        Buddy Yutting= new Buddy(lunch, "Yutting");

        Tityz.start();
        Thread.sleep(100); //make sure Tityz got it first
        Michael.start();
        Yutting.start();
       
        Thread.sleep(1000);

        // why still hanging? rob him
        Tityz.interrupt();

        // ask michael to other food
        Michael.interrupt();
    }
}

Logger:
package concurrent.lunch;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Logger {
    private static final SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss");
    public static void log(String msg) {
        System.out.println(df.format(new Date()) + " "
                + Thread.currentThread().getName() + ":\t" +msg );
    }
}

好了, 开始宴会吧.
02:42:24 Tityz:        hah, I got the scoop
02:42:25 Tityz:          someone rob my scoop, 55~~~
02:42:25 Michael:    Some one call me for better food ^^
02:42:25 Yutting:     hah, I got the scoop
02:42:25 Michael:    I will wait for a while to dip, see if any other better...
02:42:25 Tityz:          I will wait for a while to dip, see if any other better...
02:42:30 Yutting:     I got delicious food
02:42:30 Tityz:          hah, I got the scoop
02:42:35 Tityz:          I got delicious food
02:42:35 Michael:    hah, I got the scoop
02:42:40 Michael:    I got delicious food

结果显而易见, 首先是Tityz拿到勺子, 但是因为"舀"比较花时间, 其他人都只能等. 不过一段时间(1s)过去了, 其他人忍不住了, "抢"了他的勺子, 而Michael则被叫去做其他事情了. 得渔利者Yutting也. Yutting搞定后, Tityz再次抢到勺子(这里的次序是随机的), 这次没人打断他了, Michael则最后才喝到汤.

例子完了, 但是我们应该考虑到问题是, 这个锁定, 到底锁定的对象是什么? ReentrantLock.lock()没有参数, 不想synchronized(xx)可以指定被锁定的对象. 那么我们只能假设ReentrantLock.lock()维护了内部的对象. 显然, 如果我们new了好几个ReentrantLock实例并且每个线程分别持有一个, 那么这些线程最终获取的锁定的对象就不是同一个. 这就是上面例子的Party里共用一个ReentrantLock的原因.

当然, 共用的形式不一定就是通过直接传递ReentrantLock对象给某个线程, 也可以是在线程执行的方法去共用ReentrantLock, 自己发挥想象力吧

同时也说一下上面代码的缺点, 留意一下上面代码Lunch.dip()的方法签名, public boolean dip(), 是带有返回值的, 这样的做法可谓喜忧参半, 好的一面是, 如果失败了, 调用该方法的线程有机会进行其他事情的处理, 不利的一面是调用该方法的线程被逼要使用不断尝试的方式来处理, 增加了代码复杂度.

我们有一种解决上述问题的做法, 就是让调用的线程等待, 直到条件满足为止. 可以参考java.util.concurrent.locks.Condition类的使用例子.
转自:http://hi.baidu.com/iwishyou2/blog/item/4c6119296e929ff699250a8a.html
分享到:
评论

相关推荐

    ReentrantLock与synchronized

    - 修饰代码块:可以指定锁定的对象,通常用于同步类中的非静态成员变量。 3. **优势**: - 使用简单,无需额外的API依赖。 - 自动释放锁,当线程执行完同步代码块或方法后,会自动释放锁。 4. **局限性**: - ...

    Lock、Synchoronized和ReentrantLock的使用

    Synchronized 的实现是基于锁机制的,它会锁定一个对象的监视器,以便防止其他线程访问该对象。Synchronized 的优点是易于使用和理解,编译器通常会对其进行优化,可以提高性能。然而,Synchronized 也有一些缺点,...

    深入java并发编程,使用ReentrantLock和 Synchronized加锁

    `synchronized`是Java内置的原生锁,它提供了对方法或代码块的锁定,使得在任何时刻只有一个线程能够执行特定的代码。synchronized有以下特性: 1. **互斥性**:当一个线程进入一个由synchronized修饰的方法或代码...

    Java对象锁和类锁全面解析(多线程synchronize

    首先,对象锁是针对对象级别的锁定,它保护的是实例方法或者一个特定的代码块。当一个线程进入一个由`synchronized`修饰的实例方法或代码块时,它会获取到该对象的锁,其他试图访问同一锁的线程将被阻塞,直到持有锁...

    Java多线程中ReentrantLock与Condition详解

    * 使用ReentrantLock时,JVM不能包括锁定信息在线程转储中,对调试不太友好。 Condition是ReentrantLock的一个伴随类,提供了对线程的等待和唤醒等操作。Condition对象可以通过Lock对象的newCondition()方法创建,...

    Java多线程-多线程知识点总结和企业真题

    - 使用`ReentrantLock`的`newCondition()`方法创建`Condition`对象,然后使用`await()`和`signal()`方法实现线程间的等待和通知。 5. **死锁** - **题1**:什么是死锁? - 死锁发生在两个或多个线程互相等待对方...

    synchronized锁原理分析(一、从Java对象头看synchronized锁的状态)

    通过这个指针,虚拟机能够识别对象属于哪个类的实例。 对于数组对象,除了上述两部分外,还有一个额外的长度字段,用于记录数组的长度。 为了查看Java对象的实际内存布局,可以利用如OpenJDK的JOL(Java Object ...

    Java实习生面试复习(七):synchronized和ReentrantLock的学习

    在Java中,每个对象都有一个隐含的`monitor`(监视器)对象,线程通过`monitorenter`和`monitorexit`指令来获取和释放锁。当线程试图进入一个已锁定的监视器时,它会被阻塞,直到持有锁的线程释放锁。这种机制确保了...

    java 多线程 同步详解

    本文将深入探讨Java多线程同步的核心概念,特别是`synchronized`关键字的使用,以及锁定对象与锁定类的区别。 1. **线程安全问题** 在多线程环境中,当多个线程同时访问和修改同一份共享资源时,如果没有合适的...

    Java并发相关

    但不同的对象就像不同的厕所,线程A锁定对象A不会影响线程B锁定对象B,即使两个对象的锁都释放了,线程之间也不会发生交错,因为它们各自独立。 除了`synchronized`,Java还提供了其他并发控制工具,如`java.util....

    java常见面试问题及答案.pdf

    - **ReentrantLock**:提供比synchronized更高级别的锁定机制,支持更细粒度的锁控制,例如可中断的锁、可定时的锁等。 #### 五、JVM与性能优化 **1. JVM的主要组成部分有哪些?** - **类加载器(ClassLoader)**...

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接4.zip

    │ 06 可重入锁ReentrantLock的锁定原理.mp4 │ 07 可重入锁ReentrantLock之公平锁.mp4 │ 08 对象条件1.mp4 │ 09 对象条件2.mp4 │ 10 条件对象的注意事项.mp4 │ 11 等待唤醒机制的基本概念.mp4 │ 12 等待...

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接3.zip

    │ 06 可重入锁ReentrantLock的锁定原理.mp4 │ 07 可重入锁ReentrantLock之公平锁.mp4 │ 08 对象条件1.mp4 │ 09 对象条件2.mp4 │ 10 条件对象的注意事项.mp4 │ 11 等待唤醒机制的基本概念.mp4 │ 12 等待...

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接1.zip

    │ 06 可重入锁ReentrantLock的锁定原理.mp4 │ 07 可重入锁ReentrantLock之公平锁.mp4 │ 08 对象条件1.mp4 │ 09 对象条件2.mp4 │ 10 条件对象的注意事项.mp4 │ 11 等待唤醒机制的基本概念.mp4 │ 12 等待...

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接2.zip

    │ 06 可重入锁ReentrantLock的锁定原理.mp4 │ 07 可重入锁ReentrantLock之公平锁.mp4 │ 08 对象条件1.mp4 │ 09 对象条件2.mp4 │ 10 条件对象的注意事项.mp4 │ 11 等待唤醒机制的基本概念.mp4 │ 12 等待...

    并发编程 70 道面试题及答案.docx

    * synchronized是Java内置关键字,在JVM层面上锁定对象,而Lock是Java类。 * synchronized可以给类、方法、代码块加锁,而Lock只能给代码块加锁。 * synchronized不需要手动获取锁和释放锁,而Lock需要手动加锁和...

    高并发多线程面试专题及答案(上).pdf

    以上内容涵盖了Java中高并发和多线程面试可能遇到的问题,包括Synchronized关键字的使用、原理、锁定对象、可重入性、JVM对锁的优化、Synchronized的公平性和非公平性、以及锁消除和锁粗化的概念。掌握这些知识点...

    2011最新Java程序员面试笔试宝典

    ### 2011最新Java程序员面试笔试宝典 ...方法时,它是否锁定该对象? 当一个线程进入一个对象的一个`synchronized`方法时,它会锁定该对象,确保其他线程不能同时进入该对象的其他`synchronized`方法。

    Java面试题和答案.pdf

    - 对于引用数据类型:比较的是对象在内存中的地址是否相同(即是否指向同一个对象)。 - **equals()**: 通常用于比较两个对象的内容是否相同,需要由子类重写该方法来定义具体的比较逻辑。 **3. 两个对象的`...

    详解Java同步—线程锁和条件对象

    条件对象是与`ReentrantLock`关联的概念,它们允许线程在满足特定条件之前等待,而不是一直保持锁定状态。在银行转账的例子中,如果账户余额不足,线程不应该继续执行转账操作,而是应该等待账户有足够的资金。使用...

Global site tag (gtag.js) - Google Analytics