解析JVM线程同步机制

Android 命令发送广播 Android 命令发送广播。 阅读详情

解析JVM线程同步机制

 

田海立

2005年12月26日

 

摘要

对多线程的支持一般是在OS级的,而Java将其做在了语言级别,这其中最吸引人的莫过于Java对线程同步(互斥与协作)的支持。本文分析了JVM(Java Virtual Machine)内部实现的监视器同步机制,并结合经典的生产者消费者同步问题,阐述Java语言级别上对此机制的支持。

关键词:同步,互斥,协作,监视器,锁
Keyword: Synchronization, Mutual Exclusion (Mutex), Cooperation, Monitor,Lock

 

目  录

摘要
目  录
知识准备
一、线程同步:互斥和协作
二、解决同步的方案
三、线程同步模型——监视器(Monitor)机制
  3.1 监视器模型
  3.2 监视器实现互斥
  3.3 监视器实现协作
四、JVM线程同步的实现
  4.1 JVM线程模型
  4.2 对象锁
  4.3 Java语言对线程同步的支持
    4.3.1 同步方法与同步语句
    4.3.2 协作——wait& notify/notifyAll
五、利用JVM线程同步解决生产者消费者问题
  5.1 生产者消费者问题相关类层次
  5.2 生产者线程——threadSynch.ProducerConsumer.Producer
  5.3 消费者线程——threadSynch.ProducerConsumer.Consumer
  5.4 主程序——threadSynch.ProducerConsumer. ProducerConsumer
  5.5 程序运行时的一个快照
六、总结
参考资料及进一步阅读
关于作者

 

知识准备

阅读本文前,你应该具有操作系统的基本知识,知道Java的基本运行模式,最好还有过多线程的编程经验。这些知识准备,可以阅读本文后面所附的参考资料。

一、线程同步:互斥和协作

早期,顺序程序设计(Sequential Programming)的模式一般是串行的执行“输入——处理——输出”,执行过程中可能还有用户的交互或者执行其它I/O操作,而这一切直到最后的输出,系统最珍贵的CPU资源都由这个程序对应的进程(Process)占有。为了提高CPU的利用率和任务的并行化,引入了并发程序设计(ConcurrentProgramming),也就相应的在OS内部有了并发进程的概念。在支持线程(Thread)的系统中,进程的实现和思考方法也适用,只是在OS调度的最小单元和资源的分配单元上有所区别。但是也要看对线程的支持实现在哪一级上,所以也就有了三种线程实现方式:内核级线程、用户级线程和混和式线程。(关于这方面的知识,可阅读参考文献中的1或2)

支持多线程的系统中,并发线程在运行过程时,会有同步(Synchronization)的需求,同步包括了互斥(Mutual Exclusion,简记为Mutex)与协作(Cooperation)两个方面。多个线程交叉访问临界资源的时候,如果不把临界区进行互斥管理,执行的结果可能就不是你预想的(这种没有对临界资源进行互斥访问而出现的情况,你几乎可以在任何讲述并发编程的书中找到例子,这里不再赘述),这就需要将多个线程对临界区的执行串行化。两个或多个线程运行中,可能要协作完成一整件事,但是它们是相对独立运行的,相互之间并不影响,所以需要某种机制使某个线程知道它下一步执行所依赖的条件是不是满足,而这个条件是否满足是要看另外一个线程的执行情况的,也就是通过某种协作机制使线程在单独执行并行化的基础上,实现多个线程的协作串行执行。

二、解决同步的方案

解决线程同步问题,早期的科学家提出了一些对于临界区管理的方法,后来在操作系统中实现了信号量机制来解决经典的同步问题,在IEEE的POSIX(Portable Operating Systems Interface)标准中就进一步把线程进行了标准化,简称pThread标准,这其中也标准化了线程同步机制——互斥量等,目前很多类UNIX(UNIX-like)操作系统都已经实现了pThread。

实现临界区的管理可以采用软件方法,也可以用硬件方法。T.Dekker和G.L.Perterson分别提出了Dekker算法和Perterson算法,用软件方法实现了对临界区管理。硬件方法可以采用关中断来解决,但是这种方式使系统效率大大的降低,甚至如果关中断处理不当,还会使系统无法正常调度,而且也不适用于多处理器情况。现在几乎所有的操作系统都实现了信号量(Semaphore)机制。信号量(Semaphore)通过一个记录当前使用情况的标记value,等待该信号量的线程队列queue和相应的PV操作原语实现同步。P操作相当于线程要使用该信号量所标志的资源,通过P操作来获得,如果当前不可用,该线程就要被挂起;V操作相当于线程使用完该信号量所标志的资源,通过该操作来释放它,如果有线程在等待这个资源并且资源当前可用,就采取某种策略选择一个等待的线程,让它拥有该资源,并继续执行。根据value的初始值,信号量可以用来实现线程的互斥与协作。POSIX pThread的互斥量(Mutex)其实是信号量的一种特殊形式,但是使用互斥量要比用通用的信号量的同步机制来得容易。

Java利用JVM对线程执行期的完全控制,实现了监视器(Monitor)机制的线程同步,下面章节先介绍监视器机制,然后分析监视器机制在JVM中的实现。

三、线程同步模型——监视器(Monitor)机制

监视器支持上文所述的两种线程同步:互斥与协作,而JVM通过对象锁实现了监视器机制。本节就来阐述监视器模型,并分析它如何实现线程的互斥与协作。

3.1 监视器模型

 

 图一、监视器模型

图一、监视器模型

 

图一是监视器模型,监视器包括了三个部分,入口区、拥有区和等待区,入口区和等待区内可能有多个线程,但是任何时刻最多只有一个线程拥有该监视器。

线程对监视器的操作原语如下:
-“进入”监视器指线程进入入口区,准备获取监视器,此时如果没有别的线程拥有该监视器,则这个线程拥有此监视器,否则它要在入口区等待;
-“获取”监视器指在入口区和等待区的线程按照某种策略机制被选择可拥有该监视器时的操作;
-“拥有”监视器的线程在它拥有该监视器的时候排他地占有它,从而阻止其它线程的进入;
-“释放”监视器拥有监视器的线程执行完监视器范围内的代码或异常退出之后,要释放掉它所拥有的此监视器。

监视器实现的是对临界区的管理,对临界区调度原则有16字要求——无空等待,有空让进,择一而入,算法可行。展开来说就是:

-一次至多一个线程能够在临界区内;
- 不能让一个线程无限地留在临界区;
- 不能强迫一个线程无限地等待进入临界区;
- 不能因所选的调度策略而造成线程的饥饿(Starving),甚至死锁(Dead Lock)。

下面以经典的“生产者-消费者问题”为例,来分析利用监视器如何实现生产者进程与消费者进程之间的互斥与协作。简化后的该问题的描述如下:生产者进程和消费者进程都对同一个缓冲区操作,生产者生产产品放到缓冲区,消费者消费缓冲区内的产品;如果缓冲区非空,则消费者读取缓冲区的产品,消费掉产品的同时将缓冲区清空,否则消费者等待;如果缓冲区为空,则生产者生产产品放到缓冲区,否则生产者等待。

3.2 监视器实现互斥

利用监视器实现进程之间的互斥理解起来非常简单。生产者消费者问题中的缓冲区是临界资源,需要互斥访问,可以用一个监视器来保护。生产者或消费者要访问该共享的缓冲区首先必须拥有这个监视器,在监视器被别的线程占有时,该访问线程必须在入口区或等待区等待。生产者和消费者对缓冲区的互斥访问关系如图二所示。

 

 图二、生产者-消费者之间的互斥

图二、生产者-消费者之间的互斥

 

生产者与消费者各自独立地执行,只有当它们需要访问缓冲区(存放生产的产品或消费产品)的时候,才需要获得与该缓冲区关联的监视器,如果当前该监视器不能获得,它们就在监视器的入口区等待。它们在离开临界区的时候,释放监视器,以允许其它竞争该监视器的线程进入。如果一个线程已经获得了监视器,但是缓冲区的内容却还不满足自己的需要,它就必须等待并释放掉监视器,从而允许其它线程进入,关于线程协作的问题参考下面的小节。

3.3 监视器实现协作

       上面小节主要说明了生产者和消费者对缓冲区的互斥访问关系,但是没有详细谈到“wait & Release the Monitor”这个活动,这个主要牵涉了监视器实现的线程间的协作关系。

生产者和消费者通过监视器协作完成生产者消费者问题的活动图如图三所示。

 

 图三、生产者-消费者之间的协作

图三、生产者-消费者之间的协作

 

重点关注图中的绿色部分,拥有监视器的线程检测到当前缓冲区不符合自己要求的情况下“wait & Release the Monitor”,这样这个线程就释放掉了该监视器,并且进入到等待区。假设这个线程是生产者Thread_p,此时无论消费者线程Thread_c处于入口区还是等待区,Thread_c都可能获得该监视器并继续执行。Thread_c消费完产品并设置好缓冲区之后,它通知(notify/notifyAll)等待区的线程,正在等待(wait)的线程要求的条件满足后可以竞争获取监视器,并继续执行。

注意,等待线程并不是收到notify消息立即就能获取监视器,还要等发送notify消息的线程离开临界区(此时,已经释放监视器)时它才能竞争获取。这里的“竞争获取”指的是处于入口区和等待区的线程按照某种调度策略被选择进入监视器,这种策略可以是用先入先出(FIFO)队列实现的先来先服务管理,但采用哪种实现要看虚拟机的具体实现。因为这种等待线程的竞争获取监视器现象的存在,等待线程在拥有监视器之后要判断当前条件是否真的满足需要——状态有可能被先于它获得监视器的其它线程改变。

四、JVM线程同步的实现

JVM通过对象锁实现监视器的模型的线程同步机制。其实现是通过在JVM内部为每个对象和类都关联一个锁;语言层次上用同步方法或同步语句标识临界区,每个对象都实现等待/通知方法等方式来通过实现线程同步的。

4.1 JVM线程模型

Java中的线程是在用户级实现的,即,在操作系统看来JVM是一个进程,而Java线程是JVM内部实现的,对OS内核来说是透明的。这种实现可以利用JVM对Java线程执行期的完全控制在JVM和Java语言上实现线程的同步。其实现也就是图四中的2)用户级线程(User Level Thread/ULT)。

 

 

图四、线程模型

 

图四中,用户级线程(User Level Threads/ULT),对OS内核来说是透明的;内核级线程(Kernel LevelThreads/KLT)在用户空间和内核空间有相应线程的对应关系。JVM的一个实例,在内核空间只有一个OS进程与其对应,而Java内部实现的线程对OS来说都是不可见的,是实现在JVM内部的用户级线程。

4.2 对象锁

对JVM内部非私有数据的保护,JVM采用的是为每一个这样的数据对象都关联一个对象锁,这些数据主要有堆中的对象实例和方法区中的类变量。这也就是为每一个对象关联一个对象锁,来实现监视器机制的对某个对象的互斥访问和基于某个条件的协作工作。类锁的实现采用的是对象锁,不同的是,对象锁是针对java.lang.Object对象,而类锁是针对java.lang.Class对象,也就是类的实例。

JVM内部对每一个对象锁都有一个相应的计数,

-如果该计数为0,则它没有被锁,可以由访问它的线程来加锁;
- 如果该对象锁被别的线程锁定,则现在访问它的线程被挂起等待,直到锁定它的线程释放该对象锁,并且计数为0;
- 一个线程已经拥有了一个对象的对象锁,如果再次访问这个对象,则可以重入,并且这个对象锁对应的计数加一;
- 拥有对象锁的线程释放对象锁的时候,对象锁对应的计数减一;当减到计数为零时,该锁可被等待的线程竞争拥有。

由对象锁的特性可以看出,利用JVM的对象锁就实现了对被对象锁保护对象的互斥访问,是监视器模型的线程的互斥实现。当前锁定一个对象的线程也可以因等待(wait)某个条件而释放该对象锁;拥有对象锁的线程也可以在别的线程等待的某个条件满足之后通知它(notify)或它们(notifyAll),这也就实现了线程间的协作。

目前已经讨论了JVM如何实现线程同步的,但是还不知道如何进入/退出临界区,以及如何通知等待的线程实现线程协作的,这些都在Java语言上给予了支持,本文在下面章节具体介绍。

4.3 Java语言对线程同步的支持

Java语言上对线程同步的支持主要有对临界区的标识,和线程协作的支持。

4.3.1 同步方法与同步语句

Java语言对临界区的标识是通过同步方法(Synchronized Method)和同步语句(Synchronized Statements)实现的。Java线程在进入这些同步方法或同步语句标识的临界区开始的地方申请被保护对象的对象锁;离开临界区的时候(包括出现异常而离开的时候)释放掉该对象锁;如果该对象锁已经被别的线程锁定,则当前进入的线程被挂起等待。这一切是在JVM内部实现的,Java程序中要做的是用同步方法或同步语句标识临界区,并指名被保护对象,也就是对象锁所对应的对象。

同步方法是在一个类的方法的前面用synchronized关键字声明,这样标识了一个临界区,在线程访问这个类的对象的该方法的时候,就遵从锁对象的管理机制。同步语句是把某条或某几条语句用synchronized关键字标识出并指名同步语句所针对的对象。

同步方法和同步语句实现的机理是一样的,所不同的只是它们所标识区域的粒度不同,同步方法的标识的锁的粒度大于同步语句的,线程等待该锁的时间也就比较久,但是实现会比较容易,;同步方法可以指定其所管理的对象,比较灵活。所以对于同步方法或是同步语句的选择,一般原则是,对性能要求不是很高的应用层程序采用同步方法,而调度性能要求较高的底层应用,宜采用同步语句,并尽量减小其所保护的范围,当然这在提高性能的同时增加了设计的复杂度。所以这要根据你所具体应用场景的各项因素来平衡选择。

4.3.2 协作——wait & notify/notifyAll

Java语言的每个对象(都是java.lang.Object的子类)都实现了线程协作的方法,只是这些方法只有在同步方法或同步语句所标识的临界区内才能被调用,也就是调用这些方法的时候,相对应的对象已经被加锁。这种协作方式,也就如前文所述,

- 拥有对象锁(监视器)的线程调用wait释放该对象锁并等待再次进入;
- 拥有对象锁的线程执行过程中,别的线程等待的条件满足,则通知(notify)等待的线程或通知所有(notifyAll)等待的线程。

wait &notify/notifyAll的原型声明如下:

 

public final void wait() throws InterruptedException
public final native void wait(long timeout)throws InterruptedException;
public final void wait(long timeout, intnanos) throws InterruptedException
public final native void notify();
public final native void notifyAll();

 

等待某个对象锁的时候,可以指定等待的时间,超时的话,自动退出等待。

当明确知道等待区内只有一个等待线程的时候,才应该使用notify,否则就应该使用notifyAll,让JVM采用相应的调度策略来决定选择哪个等待该对象锁的线程被唤起。这样就可由JVM来保证避免某个线程无限制等待的饥饿现象,而不需要用户来关注。

五、利用JVM线程同步解决生产者消费者问题

本节以生产者消费者的实例说明JVM线程同步的设计。

5.1生产者消费者问题相关类层次

生产者消费者问题相关类层次如下图所示

 

 图五、生产者消费者问题相关类层次图

图五、生产者消费者问题相关类层次图

 

生产者(Producer)和消费者(Consumer)线程引用同一个缓冲区(Buffer)实例。缓冲区可以判断当前是否为空(isNull);非空情况下,可以从中得到产品并将其清空(getProduct);Buffer为空的情况下,可以放置产品进去(setProduct)。

5.2 生产者线程——threadSynch.ProducerConsumer.Producer

生产者线程不停地生产产品,如果缓冲区为空,放置产品到缓冲区。Producer Override Thread的run()方法,这样在调用线程的start()方法的时候,JVM线程调度机制会自动调用线程的run()方法。下面程序段是Producer.run()方法。

 

    publicvoid run() {
        super.run();

        while (true) {
            execute();
        }
    }

 

execute()是生产者的循环执行体,实现的是图三的生产者的活动,代码如下:

    private voidexecute() {

        generateNewProduct();
        System.out.println("[Producer]produced a new product: " + product);

        synchronized (buffer) {
            System.out.println("[Producer]Owned the buffer's monitor!");

            while (!buffer.isNull()) {
                System.out.println("[Producer]release the monitor and wait!");
                try {
                    buffer.wait();
                } catch (InterruptedException e){
                    e.printStackTrace();
                }

                System.out.println("[Producer]re-owned the monitor!");
            }

            System.out.println("[Producer]put the product (" + product
                    + ") into thebuffer!");
            buffer.setProduct(product);

            System.out.println("[Producer]notify other threads waiting on the monitor!");
            buffer.notifyAll();

            System.out.println("[Producer]to release the monitor!");
        }
    }

 

generateNewProduct()利用java.util.Random产生一个随机数代码生产者生产的产品。

    privatevoid generateNewProduct() {
        int prd = product;
        while ((prd = (newRandom()).nextInt(100)) == product)
            ;
        product = prd;
    }

 

5.3 消费者线程——threadSynch.ProducerConsumer.Consumer

消费者线程不停地查询缓冲区内是否有产品,如果缓冲区内有产品,则从中取出产品并清缓冲区。Consumer Override Thread.run()方法,这样在调用线程的start()方法的时候,JVM线程调度机制会自动调用线程的run()方法。Run()的实现同生产者线程,不同的是循环执行体execute(),其实现的是图三所示的消费者的活动。

 

    private voidexecute() {

        synchronized (buff) {
            System.out.println("[Consumer]Owned the monitor!");

            while (buff.isNull()) {
                System.out.println("[Consumer]release the monitor and wait!");
                try {
                    buff.wait();
                } catch (InterruptedException e){
                        e.printStackTrace();
                }

                System.out.println("[Consumer]re-owned the monitor!");
            }

            product = buff.getProduct();
            System.out.println("[Consumer]get a product (" + product
                    + ") from thebuffer!");

            System.out.println("[Consumer]notify others waiting on the monitor!");
            buff.notifyAll();

            System.out.println("[Consumer]to release the monitor!");
        }

        System.out.println("[Consumer]consume the product: " + product);
    }

 

5.4 主程序——threadSynch.ProducerConsumer.ProducerConsumer

主程序ProducerConsumer创建Buffer以及生产者和消费者线程的实例,并启动生产者和消费者线程。

 

package threadSynch.ProducerConsumer;

publicclass ProducerConsumer {
    private static Producer producer;
    private static Consumer consumer;
    private static Buffer buffer;

    public static void main(String[] args) {
       buffer = new Buffer(0);
       producer = new Producer(buffer);
       consumer = new Consumer(buffer);

       consumer.start();
       producer.start();
    }
}

 

5.5 程序运行时的一个快照

下面是上述程序运行时的一个快照,并分别以绿色和蓝色标识生产者和消费者的输出:

 

[Consumer] Owned the monitor!                                              (01)
[Consumer] release the monitor and wait!                                    (02)
[Producer] produced a new product: 43                                       (03)
[Producer] Owned the buffer's monitor!                                      (04)
[Producer] put the product (43) into thebuffer!                            (05)
[Producer] notify other threads waiting onthe monitor!                     (06)
[Producer] to release the monitor!                                          (07)
[Consumer] re-owned the monitor!                                           (08)
[Consumer] get a product (43) from thebuffer!                              (09)
[Consumer] notify others waiting on themonitor!                            (10)
[Consumer] to release the monitor!                                          (11)
[Consumer] consume the product: 43                                          (12)
[Consumer] Owned the monitor!                                              (13)
[Producer] produced a new product: 70                                       (14)
[Consumer] release the monitor and wait!                                    (15)
[Producer] Owned the buffer's monitor!                                      (16)
[Producer] put the product (70) into thebuffer!                            (17)
[Producer] notify other threads waiting onthe monitor!                     (18)
[Producer] to release the monitor!                                          (19)
[Producer] produced a new product: 43                                       (20)
[Producer] Owned the buffer's monitor!                                      (21)
[Producer] release the monitor and wait!                                    (22)
[Consumer] re-owned the monitor!                                           (23)
[Consumer] get a product (70) from thebuffer!                              (24)
[Consumer] notify others waiting on themonitor!                            (25)
[Consumer] to release the monitor!                                          (26)
[Consumer] consume the product: 70                                          (27)
[Consumer] Owned the monitor!                                               (28)
[Consumer] release the monitor and wait!                                    (29)
[Producer] re-owned the monitor!                                           (30)
[Producer] put the product (43) into thebuffer!                            (31)
[Producer] notify other threads waiting onthe monitor!                     (32)
[Producer] to release the monitor!                                          (33)
[Producer] produced a new product: 34                                       (34)
[Producer] Owned the buffer's monitor!                                      (35)
[Producer] release the monitor and wait!                                    (36)
[Consumer] re-owned the monitor!                                            (37)
[Consumer] ――――――                                                          (38)
[Producer] ――――――                                                          (39)

 

生产者消费者相关联的对象的简写表示:Per-生产者;Cer-消费者;B-缓冲区;M-缓冲区相关联的监视器;Px(x = 1, 2, …)-产品。结合图三的生产者和消费者的活动图,可以解释上面的输出快照。

-消费者Cer首先运行,获得监视器M,因缓冲区B内当前还没有产品P,所以Cer释放M并等待[Line 1, 2]。
- 生产者Per生产了一个产品P1,在获得M之后,放置P1到B并通知Cer,释放M[Line 3-7]。
- Cer重新获得M之后,从B中得到P1并清空B,通知其它线程当前B可用,释放M,消费产品P1(因为P1已经被Cer获得,所以消费P1不需要在临界区内完成),重新获得M(线程调度的作用)[Line 8-13]。
- Per生产一个新产品P2(虽然Per当前未获得M,但生产产品是不需要在临界区的,当JVM线程调度运行Per的时候,它仍然可以生产产品)[Line 14]。
- P2并未被放到B,所以Cer释放M并等待[Line 15]。
- Per现在可获得M[16],并放置P2到B[17],然后唤醒等待M的线程[18]并释放M[19];当前Cer并未获得调度运行,所以Per继续生产P3[20];Per获得M并试图放置P3到B[21],但此时Cer还未取走P2,所以Per释放M并等待[22];
- Cer…[23, …]
- Per…[line…]

六、总结

多线程有有效的利用了计算机的最珍贵的CPU资源,但在计算性能提高的基础上的同时,也增加了设计的复杂度。Java利用JVM对运行期的控制,实现了JVM内的线程模型,并简化了实现了线程间的同步问题,对编写Java程序的人员来说,开发的效率显著提高。

任何设计决策都不能用绝对的孤立的评价角度来看,它应该是各种因素的综合。JVM线程同步模型也是一样,Java开发者实现简单的代价也就丧失了灵活性。比如要在同一个类的多个方法之间实现同步,用同步方法或同步语句来实现就显得力不从心了,如果增加监视器来实现,处理不当就又可能引起死锁(Dead Lock)。

关于其它同步方法,Doug Lea实现了一个Java语言工具包。现在这个包已经加入处于JCP控制下的JSR标准。SUN Java SE 1.5实现中也已经加入了这部分代码,有兴趣的读者可以参阅。

文中所描述的生产者消费者问题的实例代码可与本文作者联系索取。

 

参考资料及进一步阅读

1) 孙钟秀,费翔林,骆斌,谢立. 操作系统教程,第三版. 高等教育出版社,2003.8
2) AbrahamSilberschatz, Peter Baer Galvin, Greg Gagne. Operating System Concepts, 6thEdition. John Wiley & Sons, Inc/高等教育出版社影印, 2002.5
3) David R. Butenhof/于磊,曾刚. Programming with POSIX Threads.Addison Wesley/中国电力出版社, 2003
4) Bill Venners著/曹晓钢,蒋靖译. Inside the Java Virtual Machine,2nd edition. McGraw-Hill/机械工业出版社, 2003
5) Ken Arnold, JamesGosling, David Holmes. The Java Programming Language, 3rd Edition.Addison Wesley/中国电力出版社影印, 2003.5
6) Michael L. Scott著/裘宗燕译. ProgrammingLanguage Pragmatics. Elsevier/电子工业出版社, 2005.3

关于作者

田海立,硕士,国家系统分析师,CSAI专业顾问。您可以通过 haili.tian@csai.cn 或 haili.tian@gmail.com 与他联系,到 http://blog.youkuaiyun.com/thl789/ 看他最新的文章。

 

(本文可自由转载,但请给出原文链接: http://blog.youkuaiyun.com/thl789/archive/2005/12/30/566494.aspx)。

基于java的广播和接收的程序 代码自己敲得,一个基于udp的广播和接受的程序 立即下载

相关推荐

Qt QWebEngine实战:手把手教你将Vue3/React前端项目嵌入C++桌面程序

本文详细介绍了如何利用Qt的QWebEngine模块将Vue3/React前端项目无缝嵌入C++桌面程序,实现现代前端框架与原生C++的深度整合。通过环境准备、项目架构设计、前端适配、Qt端集成、双向通信建立及性能优化等步骤,开发者可以高效构建兼具Web灵活性和本地系统能力的混合应用。

weixin_28736355的博客 390

【Java并发编程】synchronized(七):重量级锁原理分析

在文章的开头先明确几个概念: 并发:多个线程同时操作同一个对象,并要修改其实例变量 final修饰的实例变量线程安全,因为不可变只能初始化一次 锁:OS的调度无法满足同步的需求,需要程序通过调度算法协助调度 synchronized:jvm级别锁 Lock:api界别 synchronize:对象的锁,锁的代码 通过只允许一个线程执行sync内代码,保证了可见性,有序性,原子性 并发要求线程交替执行(时间片),而拿了锁会一直将任务执行完再释放(即使n时间片) java的线程通信实际是共

A minor 3720

RAG-Anything 实战指南:从零构建企业级多模态知识库

本文是RAG-Anything的实战指南,详细介绍了如何从零构建企业级多模态知识库。通过一体化框架,它能无差别解析文本、表格、图片、公式等多格式文档,并构建可深度理解和智能检索的知识图谱。指南涵盖了环境搭建、核心实战、智能查询及生产级部署优化,帮助企业将杂乱文档转化为智能知识大脑。

pandas7gardener的博客 242

【JUC】Synchronized及JVM底层原理

每个monitor对象拥有一个锁计数器和一个指向持有该锁的线程的指针。在Java早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的Mutex Lock来实现的,挂起线程和恢复线程都需要转入内核态去完成,阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态切换需要耗费处理器时间,如果同步代码块中内容过于简单,这种切换的时间可能比用户代码执行的时间还长”,时间成本相对较高,这也是为什么早期的synchronized效率低的原因。

qq_61887118的博客 1245

重塑计算的五层蛋糕:解读黄仁勋CES2026演讲背后的AI新秩序与物理世界

2026年CES演讲揭示AI新纪元:从语言模型到物理智能 NVIDIA CEO黄仁勋在2026年CES演讲中描绘了计算产业的根本性变革。核心突破包括: 计算范式转移:从指令执行转向意图理解,智能体系统崛起 物理AI突破:发布Cosmos世界模型,通过合成数据训练AI理解物理定律 全新VeraRubin计算平台:6芯片协同设计,解决摩尔定律放缓与AI需求增长的矛盾 自动驾驶革命:推出具备推理能力的Alpamayo模型,实现L4级自动驾驶 演讲标志着AI正从数字世界迈向物理世界,NVIDIA通过全栈布局,正在重

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 1273

C语言程序设计——单词的统计和替换

【任务描述】 对任意一篇英文文章,统计其中每个单词分别出现了多少次,并可替换指定的单词。⑶ 对单词进行替换时,允许用户选择全部替换或逐个替换。替换完成后,将文章保存到文件。⑴ 英文文章以文件形式输入。⑵ 统计的结果保存到文件。

m0_60738889的博客 810

Android之定向广播

Android中当多个应用都接收同一个广播时,会导致很多系统进程同时开启,这会导致系统卡顿。有了ssp我们可以定向的接收或发送某一特定广播达到优化系统的效果。 接收或发送定向广播需要用到android:ssp属性用于匹配URI,ssp代码“scheme-specific part”,意思是代表的东西都在scheme之后出现,如URI是“http://example.com.a”,可以分成sche

不落航班 3884

C语言试题一之计算并输出n(包括n)以内能被5或9整除的所有自然数的倒数之和

1、题目 计算并输出n(包括n)以内能被5或9整除的所有自然数的倒数之和 2、源代码实现 #include <stdio.h> #include <math.h> double fun1(int n) { if (n <= 0) return 0; int i; double sum = 0.0; for (i = 1; i <= n;...

码莎拉蒂 1万+

Android使用adb命令向APP发送特定广播

Android使用adb命令向APP发送特定广播

y280903468的博客 1711

注意力机制模块:CA(坐标注意力)二次创新:融合深度可分离卷积,打造 CADS 模块

本文提出CADS模块,将坐标注意力(CA)与深度可分离卷积(DSC)深度融合,优化移动端AI部署效率。通过重构CA的计算范式,用深度卷积替代传统1×1卷积,在保持精度的同时显著降低计算开销。文章深入分析了CA的计算瓶颈和DSC的实际效率问题,详细阐述了CADS的设计原理与PyTorch实现,并提供了多组性能对比数据。该模块可直接应用于YOLO、UNet等主流模型,为移动端AI部署提供高效解决方案。

ZXSXJ的博客 96

《PCI Express体系结构导读1》-- PCI简介

请先阅读完一遍此书再来看文章哦,这样效率更高~

HoneyIC的博客 152

解析JVM线程同步机制&& Android中的广播也定向

http://blog.youkuaiyun.com/thl789/article/details/566494 解析JVM线程同步机制   田海立 2005年12月26日   摘要 对多线程的支持一般是在OS级的,而Java将其做在了语言级别,这其中最吸引人的莫过于Java对线程同步(互斥与协作)的支持。本文分析了JVM(Java Virtual Machine)内部实现的监视器同步机制,

Gabby 1083

【QGIS入门实战精品教程】1.2:QGIS与ArcGIS的区别和联系

以下是GISGeography官方给出的两者之间的27点比较(译): 官方网址:https://gisgeography.com/qgis-arcgis-differences/ 1.QGIS容纳更多的数据格式 ArcGIS没有支持所有的数据格式,毫无疑问,QGIS在处理各种类型的数据时非常顺手,QGIS在数据格式方面是个多面手,在使用数据方面是它的长处。 QGIS使用GDAL/OGR库来读取和写入地理信息数据格式,支持超过70种矢量格式。QGIS一开始就是为了与PostGIS协作而诞生的,而支持的名单.

智慧空间实验室 2040

JVM线程同步机制解析与最佳实践

线程同步是多线程编程中的核心概念,它解决了多线程环境下的数据竞争和可见性问题。Java内存模型(JMM)定义了线程与内存的交互规范,而happens-before原则则确保了操作的有序性。在JVM中,synchronized关键字和java.util.concurrent包提供了多种同步工具,如ReentrantLock和Atomic类,它们各有适用场景。理解这些同步机制的原理和差异,对于开发高性能、线程安全的Java应用至关重要。在实际开发中,生产者-消费者模式是典型的线程协调场景,而BlockingQu

weixin_30753873的博客 348

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

JVM与多线程全面解析

JVM多线程机制深度解析 本文全面剖析了JVM多线程实现的核心机制,主要内容包括: 基础架构:详细讲解JVM线程模型(1:1模型为主)和各内存区域的线程共享特性 线程管理:通过状态转换图展示Java线程生命周期及JVM内部实现原理 同步机制:深入分析synchronized实现原理和锁优化技术(偏向锁/轻量级锁等) 内存模型:解读JMM规范中的内存交互操作和happens-before规则 高级特性:介绍现代JVM的纤程(Loom)和结构化并发等创新技术 实践建议:提供线程池使用、锁粒度控制等优化建议和关键

weixin_47242663的博客 901

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java源码解析:深入理解JVM与并发编程

本文深入解析了Java源码中的JVM与并发编程机制,通过实用的代码示例和图表,帮助你更好地理解Java的高级特性。无论是JVM的内存管理、垃圾回收机制,还是Java的线程同步、并发容器与工具类,都是Java开发者必须掌握的核心知识。希望本文能够对你的Java学习之路有所帮助!

shejizuopin的博客 508

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

多线程状态下使用同步机制的本质原因

简述 在Java的学习中必然会遇到多线程和同步问题,对于初学者一般只会理解到相关api的使用,但是很少能够真正知道为什么要对多线程环境下的对象进行同步,接下来我就谈谈自己的一些理解。 JVM堆与JVM栈宏观室是分离的,而微观上则又相互联系,这种分配方式使得JVM堆中的内容可以被多个JVM栈共享(也可以理解为多个线程访问同一个或者多个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的

笃行淡言 4524

系统与JVM与线程简述

JVM在OS中的体现 1.任务管理器中的JVM 操作系统的内存条以下简称"内存" , jvm 所使用的空间是内存,其他的exe也都是运行在内存中 javaw.exe是java在windows中的启动装置之一,它和java.exe的区别是由javaw启动的java进程将在GUI中运行,而不是命令行。无论是在eclipse中运行的main方法,还是在eclipse中启动的tomcat,都是由eclipse使用javaw.exe来驱动的,所以说你看到的进程名是javaw。 但如果通过tomcat/b

Juntao 658

jvm内存结构,多线程,线程池与Java中的锁

jvm内存模型(内存结构管理) JVM内存主要分为:程序计数器,Java虚拟机栈,本地方法栈,Java堆,方法区。 1.程序计数器 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 2.本地方法栈(stack) 和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机

qq_35419179的博客 854

【JVM研习】目录大纲

书中内容来自于深入理解java虚拟机,作者周志明。 会融合自己的知识和理解来记录下来,为了赚钱而奋斗!Day Day Up !!! (一)内存管理 内存如何划分、内存溢出的原因 内存分配和垃圾回收 (二)虚拟机如何执行 数据存储和访问 类加载过程的5个阶段以及工作原理 代码执行和执行的内存管理 (三)程序编译的过程,以及代码如何优化 编译器原理 JIT编译优化技术 (四)高效并发 内...

小诚信驿站 6289

java基础: Java线程同步机制深度解析

在阿里/字节跳动级别的高并发系统中,线程同步是保证数据一致性和系统稳定性的基石。线程同步的本质是,解决由于线程交替执行导致的竞态条件(Race Condition)问题。fill:#333;color:#333;color:#333;fill:none;是否线程访问共享资源是否需要同步?获取锁临界区操作释放锁直接访问。

weixin_43290370的博客 409
上一篇: python中的map、filter、reduce函数
下一篇: Python的Lambda表达式
LiHangTong
博客等级 码龄16年 11粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值