互斥同步

/ 多线程 / 没有评论 / 321浏览

在开发多线程程序时,我们一定要保证线程的运行安全,否则,就会造成非常严重的BUG。在Java中提供了很多种方法来保证线程的运行安全,下面我们将重点了解一下。

互斥同步是解决线程安全问题时,我们主要采用的一种方法之一,在Java中最基本的互斥同步就是使用synchronized关键字。synchronized关键字在被编译器编译后,会在同步代码块的前后添加两个monitorenter和monitorexit字节码指令。并且这两个字节码指令必须要求一个reference类型的参数来指定锁定和解锁对象。在编码时,如果开发人员指定了synchronized同步代码块的参数,那么这个synchronized同步代码块的锁就是当前参数。如果开发人没有明确指定synchronized代码块的参数,那么这个synchronized代码块就会尝试自动获取锁对象,但这里的获取会分为两种情况。如果synchronized代码块修饰的是实例方法,那么自动获得的锁对象就是当前对象实例。如果synchronized代码块修饰的是静态方法,那么自动获取的锁对象就是当前对象的Class对象实例。

当虚拟机执行monitorenter字节码指令时,首先会获取synchronized代码块的锁对象,如果这个锁对象没有被锁定,那么虚拟机此时就会把当前锁的计数器的值加1。如果虚拟机执行monitorexit字节码指令时,也会相应的先获得锁对象,并把当前锁的计数器减1。当计数器的值为0时,synchronized代码块的锁就会被释放。如果在虚拟机执行时,没有获取到锁对象,那么当前线程就会等待,也就是会阻塞,直到锁对象被其它线程释放后,当前线程才可以重新获得到锁。

在虚拟机执行monitorenter和monitorexit字节码指令时,除了上述的特性外,还有其它的特性。那就是虚拟机在执行synchronized代码块时,对于同一个线程来说是可以重新获得到锁的。这句话的意思是说,synchronized代码块会阻塞其它线程获取锁对象,但并不会阻塞当前线程重新获取同一个锁对象。除了synchronized代码块有重入锁的存在。在Java中也可以用ReentrantLock来解决线程安全问题,并且ReentrantLock也支持重入锁。ReentrantLock除了满足线程同步的功能外,和synchronized代码块相比,还提供了其它的功能来满足我们日常的线程开发。主要的功能如下。

因为互斥同步最主要的工作方式是进行线程阻塞来实现的,所以互斥同步也可以叫阻塞同步。