zoukankan      html  css  js  c++  java
  • java object monitor

    1 什么是java object monitor

    每个java对象头中都有锁状态位标记。java中在使用synchronize同步的时候,肯定是涉及到某个对象的锁。因此,在考虑同步的时候,首先要想到是同步的是哪个对象的锁。

    在java字节码上,获取了某个对象的锁之后,进入时会调用monitorenter指令,在退出时会调用monitorexit指令。

    可见,java object monitor是对java对象的锁的一种抽象。它和java对象是一对一的关系的。

    在java中,通过java object monitor使得锁是和其保护的对象一一对应的。

    2 关于synchronized关键字

    它可以用来修饰普通方法,静态方法和修饰代码段。

    修饰普通方法的时候,使用的monitor就是类对应的对象的锁。

    修饰代码段的时候,使用的monitor也是类对象的对象的锁。

    而修饰静态方法时,使用的monitor是类的class对象的锁,这样的monitor只有一个。

    具体可以参考下面的博文:

    http://www.cnblogs.com/paddix/p/5367116.html

    3 为什么“只有拥有该对象的monitor的线程才可以调用该对象的wait()、notify()和notifyAll()方法”?

    因为wait()、notify()和notifyAll()是object monitor提供的函数,在语义上,没有拥有该monitor的线程是不能调用它们的。java通过抛出异常来

    保证程序在用法上满足这个语义。

    4 为什么“wait/notify”方法必须要在synchronized的方法或者段中调用呢?

    因为只有进入了synchronized方法或者方法段中的线程才拥有了该锁对象,只有拥有了该锁对象才能调用该锁对象的wait和notify方法。

    5 下面的代码在wait之后呢?被唤醒之后,是接着wait后面的执行吗?

    synchronized (object) {

        while (<condition does not hold>)

            object.wait();

         // perform actions to condition

    }

    是的,被唤醒之后,它又重新获取了该锁之后,就会接着wait后面的执行。

    例子:

    public class Test {
        public static Object object = new Object();
        public static void main(String[] args) {
            Thread1 thread1 = new Thread1();
            Thread2 thread2 = new Thread2();
             
            thread1.start();
             
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
             
            thread2.start();
        }
         
        static class Thread1 extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                    }
                    System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
                }
            }
        }
         
        static class Thread2 extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    object.notify();
                    System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
              System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
                }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                System.out.println("同步块外的逻辑"+Thread.currentThread().getName());
            }
        }
    }

    先打印Thread1中要打印的内容,然后再打印Thread2中要打印的内容。

    6 notify()和notifyAll()的使用

    第一:调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程

    将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。

    第二:除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调用该对象的

    wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。

  • 相关阅读:
    base.View.OpenParameter.CreateFrom打开历史单据的值是default
    创建日期时间大于启动日期时间
    下拉列表不显示空白选项的原因
    复制、下推、选单时计算类的实体服务规则不会执行
    选单返回数据以后会执行的事件方法
    判断单据体是否录入行
    供应商协同平台
    .net core获取运行时文件绝对路径
    gmock函数参数输出 备忘录
    リバース 終章
  • 原文地址:https://www.cnblogs.com/hustdc/p/8873024.html
Copyright © 2011-2022 走看看