代码改变世界

哒哒哒

2017-07-21 15:50  Qin奋  阅读(259)  评论(0)    收藏  举报

 1. 多线程的3中运行方式:

 2. synchronized是一个重量级锁

    

 3. sychronized的锁类型 和  位置

    java 为每个类实例和类都设置了一个锁并且遵循一定的锁机制。

    在分析sychronized 逻辑是,关键点就是分析出提供锁的对象是哪个?实例,还是类

  

    Java中每一个对象都可以作为锁,这是synchronized实现同步的基础: 

  1. 普通同步方法,锁是当前实例对象 

  2. 静态同步方法,锁是当前类的class对象 

  3. 同步方法块,锁是括号里面的对象(某个实例对象或者class对象)

  

 4.synchronized 实现原理(javap filename.class)

   同步代码块:monitorenter指令插入到同步代码块的开始位置,monitorexit指令插入到同步代码块的结束位置。

        每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令

          时尝试获取monitor的所有权,过程如下:

          1.如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

          2.如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

          3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

 

        执行monitorexit的线程必须是objectref所对应的monitor的所有者。

        monitor的进入数减1,如果减1后进入数为0。

 

   同步方法:  synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在VM字节码层面并没有任何

        特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的access_flags字段中的synchronized

        标志位置1。如果设置了,执行线程将先获取monitor。并没有通过指令monitorenter和monitorexit来完成

 

Java对象头和monitor是实现synchronized的基础:

Hotspot虚拟机的对象头主要包括两部分数据:Mark Word(标记字段)、Klass Pointer(类型指针)。

其中Klass Point是是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,

Mark Word用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键,所以下面将重点阐述

 

Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持

有的锁、偏向线程 ID、偏向时间戳等等。

 

Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。

每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),

同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。其结构如下: 

 

 JDK1.6后对synchronized的优化:

自旋锁,自适应自旋锁

锁消除

锁粗化

轻量级锁 偏向锁 锁释放     

 

 


JAVA线程操作之 wait notify notifyAll condition,生产者消费者
 
 

JAVA线程操作之 interruppt isInterrupted interruppted
(1)interrupt:调用此方法的线程的状态属性置为“interrupted”,interrupt()并不会中断一个正在运行的线程,或者说让一个running中的线程放弃CPU。
  调用此方法,如果线程处于阻塞状态,那么线程将会抛出InterruptedException异常
 应用场景:
  *this.interruppt()线程本身并不会立刻终止。程序员需要根据这个状态属性,自行决定如何进行线程的下一步活动。
   因为Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为
   了引起该线程的注意,被中断线程可以决定如何应对中断 "。所以Thread.stop(),suspend(), resume(),runFinalizersOnExit()
   被废弃了。
  *使用Thread.interrupt()中断可能永久的阻塞线程(Object.wait()、ServerSocket.accept())。
   或者需要用某种机制使得线程更早地退出被阻塞的状态.

 

  
  

 

(2)isInterrupted:线程是否中断 native 方法

(3)interrupted:*返回线程的上次的中断状态,并清除中断状态。就是如果状态位是true(isInterrupted()=true),则interrupted()返回的
     结果是true,但是同时把状态为设置成false,再调用isInterrupted()会返回false.

    *只有当前线程才能清除自己的中断位(对应interrupted()方法)  
     意思是interrupted()不可能像 TreadA.isInterrupted() 或者TreadA.interrupt()一样使用,而是在自己的run方法里面
     直接interrupted();