JVM-JMM-并发 杂记

2020-05-12  本文已影响0人  Yves_Chen

虚拟机

编译

类加载

方法调用

Java内存结构

GC

        - Full GC

          触发时机:对象分配失败时?

          

          使用串行垃圾收集器对整个堆全面压缩。

          

          G1的设计目标通过不断调优而不再需要full GC。

    - 堆空间调整

      JVM通过在Xms和Xmx之间动态调整堆大小及年轻代大小,以满足用户设置的GC暂停时间MaxGCPauseMillis和GCTimeRatio(用户线程时间/GC线程时间)的目标。

    - RSet

        - 引用关系
引用关系
        - PRT 粒度?
        - 关系维护

          维护时机:

          对象引用关系变化时(包括引用赋值、GC移动对象等),触发写栅栏代码,维护Rset。

          

          若发生一个跨区引用关系变化,G1垃圾收集器会将相应的card加入到“脏卡片队列”。“并发优化线程”会扫描队列中的卡片来更新RSet。当“并发优化线程”来不及处理不过来时,会挂起用户线程,让用户线程也加入到更新Rset。

    - 全局卡片表
全局卡片表
      在任意收集周期,扫描Rset与PRT时,会将扫描到的引用记录标记到全局卡片表,避免重复扫描。在收集周期的最后将该表清空,显示为Clear CT。

    - 工作窃取机制
    - 收集活动图
收集活动图

深入并发

Java内存模型

  volatile操作具有原子性,包括对于64位的double或long类型变量。

  

  可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

  原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

  

  volatile引用或数组,volatile只能保证引用和数组引用的可见性,对于引用指向的对象、对象的属性、数组的元素,均不能保证可见性。

- synchronized

  pre code A...

  sync{

    临界区 B...

  }

  after code C...

  顺序一致性,通过临界区前后插入蔽障,保证三个区域代码顺序执行,A happens before B,B happens before C...,但ABC区域内部允许重排序。

- final

java关键字功能、性能

CPU缓存带来的问题

锁的一种实现

public class Counter{

public class Lock{

private boolean isLocked = false;



public synchronized void lock()

    throws InterruptedException{

    while(isLocked){

        wait();

    }

    isLocked = true;

}



public synchronized void unlock(){

    isLocked = false;

    notify();

}

}

    public synchronized void lock()

        throws InterruptedException{

        Thread callingThread =

            Thread.currentThread();

        while(isLocked && lockedBy != callingThread){

            wait();

        }

        isLocked = true;

        lockedCount++;

        lockedBy = callingThread;

    }

  

    public synchronized void unlock(){

        if(Thread.curentThread() ==

            this.lockedBy){

            lockedCount--;

  

            if(lockedCount == 0){

                isLocked = false;

                notify();

            }

        }

    }

  

    ...

  }

- 公平

  public class FairLock {

      private boolean           isLocked       = false;

      private Thread            lockingThread  = null;

      private List<QueueObject> waitingThreads =

              new ArrayList<QueueObject>();

  

    public void lock() throws InterruptedException{

      QueueObject queueObject           = new QueueObject();

      boolean     isLockedForThisThread = true;

      synchronized(this){

          waitingThreads.add(queueObject);

      }

  

      while(isLockedForThisThread){

        synchronized(this){

          isLockedForThisThread =

              isLocked || waitingThreads.get(0) != queueObject;

          if(!isLockedForThisThread){

            isLocked = true;

             waitingThreads.remove(queueObject);//加到锁的线程移除唤醒对象

             lockingThread = Thread.currentThread();

             return;

           }

        }

        try{

          queueObject.doWait();

        }catch(InterruptedException e){

          synchronized(this) { waitingThreads.remove(queueObject); }

          throw e;

        }

      }

    }

  

    public synchronized void unlock(){

      if(this.lockingThread != Thread.currentThread()){

        throw new IllegalMonitorStateException(

          "Calling thread has not locked this lock");

      }

      isLocked      = false;

      lockingThread = null;

      if(waitingThreads.size() > 0){

        waitingThreads.get(0).doNotify();

      }

    }

  }

  

  public class QueueObject {

  

      private boolean isNotified = false;

  

      public synchronized void doWait() throws InterruptedException {

  

      while(!isNotified){

          this.wait();

      }

  

      this.isNotified = false;

  

  }

  

  public synchronized void doNotify() {

      this.isNotified = true;

      this.notify();

  }

  

  public boolean equals(Object o) {

      return this == o;

  }

  

  }
public synchronized void lockRead() 

    throws InterruptedException{

    while(writers > 0 || writeRequests > 0){

        wait();

    }

    readers++;

}



public synchronized void unlockRead(){

    readers--;

    notifyAll();

}



public synchronized void lockWrite() 

    throws InterruptedException{

    writeRequests++;



    while(readers > 0 || writers > 0){

        wait();

    }

    writeRequests--;

    writers++;

}



public synchronized void unlockWrite() 

    throws InterruptedException{

    writers--;

    notifyAll();

}

}

并发集合、线程池

零散知识点

常用命令

String

反射&代理&注解

- 简单原理

  JVM创建一个代理类:
  public final class $Proxy0 extends Proxy implements List
  代理类保存InvocationHandler对象:
  public $Proxy(InvocationHandler invocationhandler)
  {
    super(invocationhandler);
  }
  代理类实现接口:
  public final List_Method()
  {
    super.h.invoke(this, m3, null); 
    // 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法
  }

序列化

1、在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。

2、通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化

3、虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)

4、序列化并不保存静态变量。

5、要想将父类对象也序列化,就需要让父类也实现Serializable 接口。

6、Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

7、服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

上一篇 下一篇

猜你喜欢

热点阅读