
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
并发编程开发是目前大多数软件编程开发项目都需要实现的一个编程开发需求,而本文我们就通过案例分析来简单了解一下,并发编程开发需要注意哪些编程问题。
在并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。
在操作系统中,一般有如果I/O操作时,对于阻塞和非阻塞是从函数调用角度来说的,其中:
阻塞:如果读写操作没有就绪或者完成,则函数一直等待。
非阻塞:函数立即调用,然后让应用程序轮询循环。
而同步和异步则是从“读写是主要是由谁完成”的角度来说的,其中:
同步:读写操作主要交给应用程序完成
异步:读写操作主要由操作系统完成,一般完成之后,回调函数和事件通知应用程序。
其中,信号量机制(Semaphores)是用来解决同步/互斥的问题的,但是信号量(Semaphore)的操作分散在各个进程或线程中,不方便进行管理,因每次需调用P/V(来自荷兰语proberen和verhogen)操作,还可能导致死锁或破坏互斥请求的问题。
由于PV操作对于解决进程互斥/同步编程复杂,因而在此基础上提出了与信号量等价的——“管程技术”。
其中,管程(Monitor)当中定义了共享数据结构只能被管程内部定义的函数所修改,所以如果我们想修改管程内部的共享数据结构的话,只能调用管程内部提供的函数来间接的修改这些数据结构。
一般来说,管程(Monitor)和信号量(Semaphore)是等价的,所谓等价指的是用管程能够实现信号量,也能用信号量实现管程。
在管程的发展历程上,先后出现过Hasen模型、Hoare模型和MESA模型等三种不同的管程模型,现在正在广泛使用的是MESA模型。
在MESA模型中,管程中引入了条件变量(ConditionalVariable)的概念,而且每个条件变量都对应有一个等待队列(WaitQueue)。其中,条件变量和等待队列的作用是解决线程之间的同步问题。
而对于解决线程之间的互斥问题,将共享变量(SharedVariable)及其对共享变量的操作统一封装起来,一般主要是实现一个线程安全的阻塞队列(BlockingQueue),将线程不安全的队列封装起来,对外提供线程安全的操作方法,例如入队操作(Enqueue)和出队操作(Dequeue)。
在Java领域中,对于Java语法层面实现的锁(synchronized关键字),其实就是参考了MESA模型,并且对MESA模型进行了精简,一般在MESA模型中,条件变量可以有多个,Java语言内置的管程(synchronized)里只有一个条件变量。
这就意味着,被synchronized关键字修饰的代码块或者直接标记静态方法以及实例方法,在编译期会自动生成相关加锁(lock)和解锁(unlock)的代码,即就是monitorenter和monitorexit指令。
对于synchronized关键字来说,主要是在JavaHotSpot(TM)VM虚拟机通过Monitor(监视器)来实现monitorenter和monitorexit指令的。
同时,在JavaHotSpot(TM)VM虚拟机中,每个对象都会有一个监视器,监视器和对象一起创建、销毁。
监视器相当于一个用来监视这些线程进入的特殊房间,其义务是保证(同一时间)只有一个线程可以访问被保护的临界区代码块。
本质上,监视器是一种同步工具,也可以说是JVM对管程的同步机制的封装实现,主要特点是:
同步:监视器所保护的临界区代码是互斥地执行的。一个监视器是一个运行许可,任一线程进入临界区代码都需要获得这个许可,离开时把许可归还。
协作:监视器提供Signal机制,允许正持有许可的线程暂时放弃许可进入阻塞等待状态,等待其他线程发送Signal去唤醒;其他拥有许可的线程可以发送Signal,唤醒正在阻塞等待的线程,让它可以重新获得许可并启动执行。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请加danei0707学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。