monitor_monitoring - CSDN
精华内容
参与话题
  • 本篇文章给大家带来的内容是关于Monitor(管程)是什么意思?Java中Monitor(管程)的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 monitor的概念 管程,英文是 Monitor,也常被翻译为...

    本篇文章给大家带来的内容是关于Monitor(管程)是什么意思?Java中Monitor(管程)的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

    monitor的概念

    管程,英文是 Monitor,也常被翻译为“监视器”,monitor 不管是翻译为“管程”还是“监视器”,都是比较晦涩的,通过翻译后的中文,并无法对 monitor 达到一个直观的描述。
    在《操作系统同步原语》 这篇文章中,介绍了操作系统在面对 进程/线程 间同步的时候,所支持的一些同步原语,其中 semaphore 信号量 和 mutex 互斥量是最重要的同步原语。
    在使用基本的 mutex 进行并发控制时,需要程序员非常小心地控制 mutex 的 down 和 up 操作,否则很容易引起死锁等问题。为了更容易地编写出正确的并发程序,所以在 mutex 和 semaphore 的基础上,提出了更高层次的同步原语 monitor,不过需要注意的是,操作系统本身并不支持 monitor 机制,实际上,monitor 是属于编程语言的范畴,当你想要使用 monitor 时,先了解一下语言本身是否支持 monitor 原语,例如 C 语言它就不支持 monitor,Java 语言支持 monitor。
    一般的 monitor 实现模式是编程语言在语法上提供语法糖,而如何实现 monitor 机制,则属于编译器的工作,Java 就是这么干的。

    monitor 的重要特点是,同一个时刻,只有一个 进程/线程 能进入 monitor 中定义的临界区,这使得 monitor 能够达到互斥的效果。但仅仅有互斥的作用是不够的,无法进入 monitor 临界区的 进程/线程,它们应该被阻塞,并且在必要的时候会被唤醒。显然,monitor 作为一个同步工具,也应该提供这样的管理 进程/线程 状态的机制。想想我们为什么觉得 semaphore 和 mutex 在编程上容易出错,因为我们需要去亲自操作变量以及对 进程/线程 进行阻塞和唤醒。monitor 这个机制之所以被称为“更高级的原语”,那么它就不可避免地需要对外屏蔽掉这些机制,并且在内部实现这些机制,使得使用 monitor 的人看到的是一个简洁易用的接口。

    monitor 基本元素

    monitor 机制需要几个元素来配合,分别是:

    1.临界区

    2.monitor 对象及锁

    3.条件变量以及定义在 monitor 对象上的 wait,signal 操作。

    使用 monitor 机制的目的主要是为了互斥进入临界区,为了做到能够阻塞无法进入临界区的 进程/线程,还需要一个 monitor object 来协助,这个 monitor object 内部会有相应的数据结构,例如列表,来保存被阻塞的线程;同时由于 monitor 机制本质上是基于 mutex 这种基本原语的,所以 monitor object 还必须维护一个基于 mutex 的锁。
    此外,为了在适当的时候能够阻塞和唤醒 进程/线程,还需要引入一个条件变量,这个条件变量用来决定什么时候是“适当的时候”,这个条件可以来自程序代码的逻辑,也可以是在 monitor object 的内部,总而言之,程序员对条件变量的定义有很大的自主性。不过,由于 monitor object 内部采用了数据结构来保存被阻塞的队列,因此它也必须对外提供两个 API 来让线程进入阻塞状态以及之后被唤醒,分别是 wait 和 notify。

    Java 语言对 monitor 的支持

    monitor 是操作系统提出来的一种高级原语,但其具体的实现模式,不同的编程语言都有可能不一样。以下以 Java 的 monitor 为例子,来讲解 monitor 在 Java 中的实现方式。

    临界区的圈定

    在 Java 中,可以采用 synchronized 关键字来修饰实例方法、类方法以及代码块,如下所示:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    /**

     * @author beanlam

     * @version 1.0

     * @date 2018/9/12

     */

    public class Monitor {

     

        private Object ANOTHER_LOCK = new Object();

     

        private synchronized void fun1() {

        }

     

        public static synchronized void fun2() {

        }

     

        public void fun3() {

            synchronized (this) {

            }

        }

     

        public void fun4() {

            synchronized (ANOTHER_LOCK) {

            }

        }

    }

    被 synchronized 关键字修饰的方法、代码块,就是 monitor 机制的临界区。

    monitor object

    可以发现,上述的 synchronized 关键字在使用的时候,往往需要指定一个对象与之关联,例如 synchronized(this),或者 synchronized(ANOTHER_LOCK),synchronized 如果修饰的是实例方法,那么其关联的对象实际上是 this,如果修饰的是类方法,那么其关联的对象是 this.class。总之,synchronzied 需要关联一个对象,而这个对象就是 monitor object
    monitor 的机制中,monitor object 充当着维护 mutex以及定义 wait/signal API 来管理线程的阻塞和唤醒的角色。
    Java 语言中的 java.lang.Object 类,便是满足这个要求的对象,任何一个 Java 对象都可以作为 monitor 机制的 monitor object。
    Java 对象存储在内存中,分别分为三个部分,即对象头、实例数据和对齐填充,而在其对象头中,保存了锁标识;同时,java.lang.Object 类定义了 wait(),notify(),notifyAll() 方法,这些方法的具体实现,依赖于一个叫 ObjectMonitor 模式的实现,这是 JVM 内部基于 C++ 实现的一套机制,基本原理如下所示:

    当一个线程需要获取 Object 的锁时,会被放入 EntrySet 中进行等待,如果该线程获取到了锁,成为当前锁的 owner。如果根据程序逻辑,一个已经获得了锁的线程缺少某些外部条件,而无法继续进行下去(例如生产者发现队列已满或者消费者发现队列为空),那么该线程可以通过调用 wait 方法将锁释放,进入 wait set 中阻塞进行等待,其它线程在这个时候有机会获得锁,去干其它的事情,从而使得之前不成立的外部条件成立,这样先前被阻塞的线程就可以重新进入 EntrySet 去竞争锁。这个外部条件在 monitor 机制中称为条件变量。

    synchronized 关键字

    synchronized 关键字是 Java 在语法层面上,用来让开发者方便地进行多线程同步的重要工具。要进入一个 synchronized 方法修饰的方法或者代码块,会先获取与 synchronized 关键字绑定在一起的 Object 的对象锁,这个锁也限定了其它线程无法进入与这个锁相关的其它 synchronized 代码区域。

    网上很多文章以及资料,在分析 synchronized 的原理时,基本上都会说 synchronized 是基于 monitor 机制实现的,但很少有文章说清楚,都是模糊带过。
    参照前面提到的 Monitor 的几个基本元素,如果 synchronized 是基于 monitor 机制实现的,那么对应的元素分别是什么?
    它必须要有临界区,这里的临界区我们可以认为是对对象头 mutex 的 P 或者 V 操作,这是个临界区
    那 monitor object 对应哪个呢?mutex?总之无法找到真正的 monitor object。
    所以我认为“synchronized 是基于 monitor 机制实现的”这样的说法是不正确的,是模棱两可的。
    Java 提供的 monitor 机制,其实是 Object,synchronized 等元素合作形成的,甚至说外部的条件变量也是个组成部分。JVM 底层的 ObjectMonitor 只是用来辅助实现 monitor 机制的一种常用模式,但大多数文章把 ObjectMonitor 直接当成了 monitor 机制。
    我觉得应该这么理解:Java 对 monitor 的支持,是以机制的粒度提供给开发者使用的,也就是说,开发者要结合使用 synchronized 关键字,以及 Object 的 wait / notify 等元素,才能说自己利用 monitor 的机制去解决了一个生产者消费者的问题

    运行状态---wait--->等待阻塞---notify--->同步阻塞

    展开全文
  • Monitor

    千次阅读 2018-08-16 23:11:29
    什么是Monitor?我们可以把它理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。 与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的...

    什么是Monitor?我们可以把它理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。 与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做内部锁或者Monitor锁。 
    Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。其结构如下:  

    44444

    Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL; 
    EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程。 
    RcThis:表示blocked或waiting在该monitor record上的所有线程的个数。 
    Nest:用来实现重入锁的计数。 
    HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。 
    Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。 
     

     

     

    参考:

    http://cmsblogs.com/?p=2071

    展开全文
  • (九)监控模块-monitor

    千次阅读 2018-11-17 19:35:13
    先用一张图来说明dubbo中的monitor模块结构: 基于Filter来实现服务调用监控功能 @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) public class MonitorFilter implements Filter { private ...

    先用一张图来说明dubbo中的monitor模块结构:

    基于Filter来实现服务调用监控功能

    @Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
    public class MonitorFilter implements Filter {
    
        private static final Logger logger = LoggerFactory.getLogger(MonitorFilter.class);
        
        private final ConcurrentMap<String, AtomicInteger> concurrents = new ConcurrentHashMap<String, AtomicInteger>();
        
        private MonitorFactory monitorFactory;
        
        public void setMonitorFactory(MonitorFactory monitorFactory) {
            this.monitorFactory = monitorFactory;
        }
        
        // 调用过程拦截
        public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
            if (invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) { //1处
                RpcContext context = RpcContext.getContext(); // 提供方必须在invoke()之前获取context信息
                long start = System.currentTimeMillis(); // 记录起始时间戮
                getConcurrent(invoker, invocation).incrementAndGet(); // 并发计数
                try {
                    Result result = invoker.invoke(invocation); // 让调用链往下执行
                    collect(invoker, invocation, result, context, start, false); //4处
                    return result;
                } catch (RpcException e) {
                    collect(invoker, invocation, null, context, start, true);
                    throw e;
                } finally {
                    getConcurrent(invoker, invocation).decrementAndGet(); // 并发计数
                }
            } else {
                return invoker.invoke(invocation);
            }
        }
    }


    在上面代码的1处中,只有打开了监控开关时,即设置Constants.MONITOR_KEY参数时,才会进行有监控功能。

     

    通过源码com.alibaba.dubbo.config.ServiceConfig<T>的方法

     

    doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)来看看监控功能:

     

    if (registryURLs != null && registryURLs.size() > 0
                            && url.getParameter("register", true)) {
        for (URL registryURL : registryURLs) {
            url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
            URL monitorUrl = loadMonitor(registryURL); //2处
            if (monitorUrl != null) {
                url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); //3处
            }
            if (logger.isInfoEnabled()) {
                logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
            }
            Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
    
            Exporter<?> exporter = protocol.export(invoker);
            exporters.add(exporter);
        }
    } else {
        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
    
        Exporter<?> exporter = protocol.export(invoker);
        exporters.add(exporter);
    }


    在上面源码的2处,会加载标签<dubbo:monitor protocol="dubbo" address="127.0.0.1:7070" />的内容,
    如果应用设置<dubbo:monitor/>标签则,会设置URL的Constants.MONITOR_KEY属性,则在上面的MonitorFilter过滤器就会打开监控功能。

    在MonitorFilter的4处,会调用到

     

    com.alibaba.dubbo.monitor.dubbo.DubboMonitor.collect(..)方法,DubboMonitor实现了MonitorService的collect(..)方法,

     

    方法:collect(URL statistics),可以看看传参URL对象知道统计的信息是哪些:

     

    // 信息采集
    private void collect(Invoker<?> invoker, Invocation invocation, Result result, RpcContext context, long start, boolean error) {
        try {
            // ---- 服务信息获取 ----
            long elapsed = System.currentTimeMillis() - start; // 计算调用耗时
            int concurrent = getConcurrent(invoker, invocation).get(); // 当前并发数
            String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
            String service = invoker.getInterface().getName(); // 获取服务名称
            String method = RpcUtils.getMethodName(invocation); // 获取方法名
            URL url = invoker.getUrl().getUrlParameter(Constants.MONITOR_KEY);
            Monitor monitor = monitorFactory.getMonitor(url);
            int localPort;
            String remoteKey;
            String remoteValue;
            if (Constants.CONSUMER_SIDE.equals(invoker.getUrl().getParameter(Constants.SIDE_KEY))) {
                // ---- 服务消费方监控 ----
                context = RpcContext.getContext(); // 消费方必须在invoke()之后获取context信息
                localPort = 0;
                remoteKey = MonitorService.PROVIDER;
                remoteValue = invoker.getUrl().getAddress();
            } else {
                // ---- 服务提供方监控 ----
                localPort = invoker.getUrl().getPort();
                remoteKey = MonitorService.CONSUMER;
                remoteValue = context.getRemoteHost();
            }
            String input = "", output = "";
            if (invocation.getAttachment(Constants.INPUT_KEY) != null) {
                input = invocation.getAttachment(Constants.INPUT_KEY);
            }
            if (result != null && result.getAttachment(Constants.OUTPUT_KEY) != null) {
                output = result.getAttachment(Constants.OUTPUT_KEY);
            }
            //A处
            monitor.collect(new URL(Constants.COUNT_PROTOCOL,
                                NetUtils.getLocalHost(), localPort,
                                service + "/" + method,
                                MonitorService.APPLICATION, application,
                                MonitorService.INTERFACE, service,
                                MonitorService.METHOD, method,
                                remoteKey, remoteValue,
                                error ? MonitorService.FAILURE : MonitorService.SUCCESS, "1",
                                MonitorService.ELAPSED, String.valueOf(elapsed),
                                MonitorService.CONCURRENT, String.valueOf(concurrent),
                                Constants.INPUT_KEY, input,
                                Constants.OUTPUT_KEY, output));
        } catch (Throwable t) {
            logger.error("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t);
        }
    }

     

    看看上面源码的“A处”,创建的URL对象,
    protocol:count
    host:[服务模块的ip]
    port:[服务模块的端口]
    application:[服务模块的应用名]
    interface:[接口名]
    method:[方法名]
    provider:[提供者的ip] //如果服务模块角色是消息者,则会标识对方的角色是提供者,否则;不会有这个统计项
    consumer:[消息者的ip] //如果服务模块角色是提供者,则会标识对方的角色是消息者,否则;不会有这个统计项
    failure:1 //服务调用失败的次数为1
    success:1 //服务调用成功的次数为1
    elapsed:[服务调用耗时,这个是实际调用时长,单位毫秒]
    concurrent:[服务的并发数,即是同时调用了该方法,还没结果返回。]
    input:[未知]
    output:[未知]
     

    这样可以将dubbo的服务调用统计数据暂时保存到DubboMonitor的ConcurrentMap<Statistics, AtomicReference<long[]>> statisticsMap中,

    com.alibaba.dubbo.monitor.dubbo.DubboMonitor.collect(URL)源码:

    public void collect(URL url) {
        // 读写统计变量
        int success = url.getParameter(MonitorService.SUCCESS, 0);
        int failure = url.getParameter(MonitorService.FAILURE, 0);
        int input = url.getParameter(MonitorService.INPUT, 0);
        int output = url.getParameter(MonitorService.OUTPUT, 0);
        int elapsed = url.getParameter(MonitorService.ELAPSED, 0);
        int concurrent = url.getParameter(MonitorService.CONCURRENT, 0);
        // 初始化原子引用
        Statistics statistics = new Statistics(url);
        AtomicReference<long[]> reference = statisticsMap.get(statistics);
        if (reference == null) {
            statisticsMap.putIfAbsent(statistics, new AtomicReference<long[]>());
            reference = statisticsMap.get(statistics);
        }
        // CompareAndSet并发加入统计数据
        long[] current;
        long[] update = new long[LENGTH];
        do {
            current = reference.get();
            if (current == null) {
                update[0] = success;
                update[1] = failure;
                update[2] = input;
                update[3] = output;
                update[4] = elapsed;
                update[5] = concurrent;
                update[6] = input;
                update[7] = output;
                update[8] = elapsed;
                update[9] = concurrent;
            } else {
                update[0] = current[0] + success;
                update[1] = current[1] + failure;
                update[2] = current[2] + input;
                update[3] = current[3] + output;
                update[4] = current[4] + elapsed;
                update[5] = (current[5] + concurrent) / 2;
                update[6] = current[6] > input ? current[6] : input;
                update[7] = current[7] > output ? current[7] : output;
                update[8] = current[8] > elapsed ? current[8] : elapsed;
                update[9] = current[9] > concurrent ? current[9] : concurrent;
            }
        } while (! reference.compareAndSet(current, update));
    }

     

    其中的long[]就保存了各项服务调用统计数据:

    [0]:成功总数
    [1]:失败总数
    [4]:耗时总时长
    [5]:并发数
    [8]:最大耗时
    [9]:最大并发数


    DubboMonitor部分源码:

     

    private final ConcurrentMap<Statistics, AtomicReference<long[]>> statisticsMap = new ConcurrentHashMap<Statistics, AtomicReference<long[]>>();
    
        public DubboMonitor(Invoker<MonitorService> monitorInvoker, MonitorService monitorService) {
            this.monitorInvoker = monitorInvoker;
            this.monitorService = monitorService;
            this.monitorInterval = monitorInvoker.getUrl().getPositiveParameter("interval", 60000);
            // 启动统计信息收集定时器
            sendFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
                public void run() {
                    // 收集统计信息
                    try {
                        send();
                    } catch (Throwable t) { // 防御性容错
                        logger.error("Unexpected error occur at send statistic, cause: " + t.getMessage(), t);
                    }
                }
            }, monitorInterval, monitorInterval, TimeUnit.MILLISECONDS);
        }


    可以看到会以1分钟的间隔,定时发送监控统计数据到dubbo的监控模块dubbo-monitor-simple

    下面看看dubbo-monitor-simple的部分源码:

     

     

     

    private final BlockingQueue<URL> queue;
    
    public SimpleMonitorService() {
        queue = new LinkedBlockingQueue<URL>(Integer.parseInt(ConfigUtils.getProperty("dubbo.monitor.queue", "100000")));
        writeThread = new Thread(new Runnable() {
            public void run() {
                while (running) {
                    try {
                        write(); // 记录统计日志 //6处
                    } catch (Throwable t) { // 防御性容错
                        logger.error("Unexpected error occur at write stat log, cause: " + t.getMessage(), t);
                        try {
                            Thread.sleep(5000); // 失败延迟
                        } catch (Throwable t2) {
                        }
                    }
                }
            }
        });
        writeThread.setDaemon(true);
        writeThread.setName("DubboMonitorAsyncWriteLogThread");
        writeThread.start();
        chartFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                try {
                    draw(); // 绘制图表 //7处
                } catch (Throwable t) { // 防御性容错
                    logger.error("Unexpected error occur at draw stat chart, cause: " + t.getMessage(), t);
                }
            }
        }, 1, 300, TimeUnit.SECONDS);
        INSTANCE = this;
    }
    
    public void collect(URL statistics) { //5处
        queue.offer(statistics);
        if (logger.isInfoEnabled()) {
            logger.info("collect statistics: " + statistics);
        }
    }
    

     


    从5处来看,这方法收到统计数据会先入队列,
    然后在6处,会有后台线程不断地将列队的数据写入到本地文件中,

     

     

    从7处来看,间隔一段时间会从本地文件中取出数据画出图。

     


    在源码“6处”的write方法:

     

    private void write() throws Exception {
        URL statistics = queue.take();
        if (POISON_PROTOCOL.equals(statistics.getProtocol())) {
            return;
        }
        String timestamp = statistics.getParameter(Constants.TIMESTAMP_KEY);
        Date now;
        if (timestamp == null || timestamp.length() == 0) {
            now = new Date();
        } else if (timestamp.length() == "yyyyMMddHHmmss".length()) {
            now = new SimpleDateFormat("yyyyMMddHHmmss").parse(timestamp);
        } else {
            now = new Date(Long.parseLong(timestamp));
        }
        String day = new SimpleDateFormat("yyyyMMdd").format(now);
        SimpleDateFormat format = new SimpleDateFormat("HHmm");
        for (String key : types) {
            try {
                String type;
                String consumer;
                String provider;
                if (statistics.hasParameter(PROVIDER)) {
                    type = CONSUMER;
                    consumer = statistics.getHost();
                    provider = statistics.getParameter(PROVIDER);
                    int i = provider.indexOf(':');
                    if (i > 0) {
                        provider = provider.substring(0, i);
                    }
                } else {
                    type = PROVIDER;
                    consumer = statistics.getParameter(CONSUMER);
                    int i = consumer.indexOf(':');
                    if (i > 0) {
                        consumer = consumer.substring(0, i);
                    }
                    provider = statistics.getHost();
                }
                String filename = statisticsDirectory 
                        + "/" + day 
                        + "/" + statistics.getServiceInterface() 
                        + "/" + statistics.getParameter(METHOD) 
                        + "/" + consumer 
                        + "/" + provider 
                        + "/" + type + "." + key;
                File file = new File(filename);
                File dir = file.getParentFile();
                if (dir != null && ! dir.exists()) {
                    dir.mkdirs();
                }
                FileWriter writer = new FileWriter(file, true);
                try {
                    writer.write(format.format(now) + " " + statistics.getParameter(key, 0) + "\n");
                    writer.flush();
                } finally {
                    writer.close();
                }
            } catch (Throwable t) {
                logger.error(t.getMessage(), t);
            }
        }
    }

    String[] types = {SUCCESS, FAILURE, ELAPSED, CONCURRENT, MAX_ELAPSED, MAX_CONCURRENT};
    数据保存到文件:statistics/[yyyyMMdd]/[接口名]/[方法名]/[消费者ip]/[提供者ip]/[type的值"provider"或者"consumer"].[tyeps数组里值]
    文件内容保存每一分钟的值,如consumer.success文件的内容:
    1313 5
    1314 0
    1315 0
    保存了消费者分别在13时13、14、15分钟调用成功的次数。
     

    自己写了个RPC:

    https://github.com/nytta

    可以给个star,^0^.

    展开全文
  • 什么是Monitor

    2020-04-18 21:13:07
    什么是MonitorMonitor是一种实现同步的工具。 每个对象都有一个Monitor与之对应。 Monitor是实现synchronized的基础。 结构: owner:初始值为null时没有线程占用,当线程获得锁时,owner会保存线程唯一标识,被...

    什么是Monitor?

    Monitor叫监视器/管程。实现synchronized的临界区。
    每个对象都有一个Monitor与之对应。
    Monitor是实现synchronized的基础。
    结构:
    owner:初始值为null时没有线程占用,当线程获得锁时,owner会保存线程唯一标识,被释放后又置为null。
    EntryQ:关联一个系统互斥锁,阻塞失败线程。
    RC This:blocked中线程个数
    Nest:实现重入锁的计数。
    hashCode:保存从对象拷贝过来的hashCode值
    Canddidate:有两个值0和1,0表示没有需要唤醒的线程,1表示需要唤醒一个线程。

    展开全文
  • JAVA并发-Monitor简介

    千次阅读 2018-07-05 14:49:20
    什么是Monitor?1.Monitor是一种用来实现同步的工具2.与每个java对象相关联,即每个java对象都有一个Monitor与之对应3.Monitor是实现Sychronized(内置锁)的基础Monitor的基本结构是什么?1.Owner字段:初始时为NULL...
  • Monitor概念

    2020-10-06 14:24:10
    Monitor概念 Monitor 被翻译为监视器或管程 每个 Java 对象都可以关联一个 Monitor 对象, 如果使用 synchronized 给对象上锁(重量级)之后,该对象头的 Mark Word 中就被设置指向 Monitor 对象的指针 Monitor 结构...
  • 其他相关文章见:《Lock与synchronized 的区别》 《可重入锁 介绍以及原理》 介绍Synchronized之前,我们先来看一下线程安全的相关概念。 造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是...
  • Java多线程(二)——Java对象的Monitor机制

    千次阅读 多人点赞 2018-08-06 10:06:26
    Java多线程学习(二)——Java对象的Monitor机制与notify/wait方法 概述 Java虚拟机给每个对象和class字节码都设置了一个监听器Monitor,用于检测并发代码的重入,同时在Object类中还提供了notify和wait方法来对...
  • Java 中的Monitor是什么意思?

    千次阅读 2017-03-16 20:56:56
    详情参见如下链接: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
  • Java多线程--Monitor对象(一)

    千次阅读 2017-09-10 22:09:07
    1. 什么是Monitor?  Monitor其实是一种同步工具,也可以说是一种同步机制,它通常被描述为一个对象,主要特点是: 对象的所有方法都被“互斥”的执行。好比一个Monitor只有一个运行“许可”,任一个线程进入任何...
  • 如题,因为as在新版本,更名了,变为android profile,点击下图即可   如果需要打开原android-monitor可以考如下链接 打开原monitor方法
  • 当我们前面的服务都启动成功,进入dubbo admin页面之后,发现 com.alibaba.dubbo.monitor.MonitorService后面的状态是没有提供者,说明没有连上注册中心,然后我们看一下dubbo simpleMonitor的dubbo.properties文件...
  • 在android studio的内部terminal中输入monitor.前提系统环境变量配置了你的sdk路径办法二.找到你sdk的路径,路径在settings里面找到android sdk location会显示,找到sdk目录下的tool目录.打开monitor.bat文件.即可......
  • 自己的更新android studio 突然发现android device monitor不见了,一下子就懵逼了,如果google了一下。...
  • Android Studio 3.0找不到Android Device Monitor

    万次阅读 多人点赞 2018-05-29 12:55:22
    为什么Android Studio 3.0中找不到Android Device Monitor? 因为自Android Studio 3.0开始弃用Android Device Monitor,Android Developers官网上的原话是: Android Device Monitor is a standalone tool that...
  • WIN10使用 NetSpeedMonitor

    万次阅读 2017-08-12 00:22:22
    NetSpeedMonitor是一款显示网速的软件,显示在右下角通知栏的左边,界面简洁。 但是NetSpeedMonitor仅仅支持到Win7,所以Win10用户在安装的时候会遇到不兼容的情况。
  • AndroidStudio3.0打开Android Device Monitor

    万次阅读 2018-05-04 20:25:57
    相信很多更新了AndroidStudio3.0的小伙伴会...device monitor,打开DeviceMonitor。今天偶然看到Google的官方文档:However, most components of the Android Device Monitor are deprecated in favor of updated t...
  • 3Dmax2014 monitor.exe关闭问题

    万次阅读 2013-12-23 13:09:17
    前两天在安装3DMax2014的时候,会弹出一个对话框提醒我说monitor.exe正在运行,必须关闭它才能继续安装, 于是我到任务管理器中去找monitor.exe。因为后台进程有点儿多,而且那个进程的全名不叫monitor.exe,还真...
  • Microsoft Network Monitor 3.4简要说明

    万次阅读 2012-10-24 11:38:35
    第一次启动后是一个欢迎界面,左下角可以选择要监控的网络连接。 在标签栏上点击右键,可以选择关闭这个页面,或者保留这个页面,关闭... ...左边会显示所有进行网络通讯的进程,右边会显示所选进程的具体包信息。...
  • 安装完,默认Android Device Monitor图标是不在工具栏显示的,只能从Tools -&gt; Android -&gt; Android Device Monitor打开,很不方便。 所以要把图标给放到工具栏上来,下面介绍方法,看图就明白:  ...
1 2 3 4 5 ... 20
收藏数 272,634
精华内容 109,053
关键字:

monitor