[Java并发-4]Java锁相关

Java锁的类型

Java语言提供的锁的类型

  自旋锁:循环的使用CAS操作,直到成功。自旋锁是不会放弃CPU资源的。
  乐观锁:假设数据的并发操作没有冲突,所有线程都可以修改数据,在修改时判断数据和之前是否一致,一致则修改成功,不一致修改失败。
  悲观锁:假设数据的并发操作都有冲突,对数据的任何操作都采取同步。让所有的线程排队读写数据。
  独享锁:给资源加写锁,只有当前线程能够读写数据,其他线程既不能读数据,也不能写数据。小结:只有一个线程能够读写数据。
  共享锁:给资源加读锁,当前线程可以读数据,但是不能写数据。其他线程也可以对资源加读锁,但是不能加写锁。小结:多个线程能读数据,没有线程能写数据。
  可重入锁/不可重入锁:一个锁,可以锁多个资源。可重入锁是指:当线程拿到锁后,能够进入锁的同步的其他代码块中。不可重入锁是指:线程拿到锁后,不能进入锁的同步的其他代码块中,如果要进入,需要再次拿到锁。
  公平锁/非公平锁:是否按时间顺序拿到锁。公平锁就是先来后到,非公平锁就是允许插队获取锁。

同步关键字synchronized

synchronized简介

  Java语言中,每一个对象都能作为锁,具体表现形式:对于synchronized修饰的普通同步方法,锁是当前对象,如果是静态的同步方法,锁是当前类的Class对象,如果是同步代码块,锁是括号里的对象。synchronized同步的本质是,每一个对象都有一个Monitor监视器对象,通过进出Monitor,实现方法同步和代码块同步。进入Monitor的指令是monitorenter,退出Monitor的指令是monitorexit,一次只有一个线程,能够进入Monitor,其他的线程试图进入Monitor就会进入阻塞状态。synchronized不仅能保证同步,还能保证可见性和原子性。

  synchronized锁的特点是:悲观锁,独享锁,可重入锁。在一些场景下,JVM会对synchronized锁作出优化,例如锁粗化、锁消除。举2个例子。

    private int i;
    private int j;
    public void syn(){//锁粗化前
        synchronized (this) {
            i++;
        }
        synchronized (this) {
            j++;
        }
    }
    public void syn(){//锁粗化后
        synchronized (this) {
            i++;
            j++;
        }
    }
    public void test(){
        //append方法是synchronized方法,如果下面的程序是热点代码,JVM就能够消除进出Monitor的指令。因为str1是线程安全的变量。
        StringBuffer str1 = new StringBuffer();
        str1.append("a");
        str1.append("a");
        str1.append("a");
    }

synchronized加锁的原理

  在HotSpot虚拟机中,对象在内存中由三部分组成:对象头、实例数据、对齐填充。对象头中,又由三部分组成:Mark Word、Class Metadata Address、Array Length。这三者在32位虚拟机中,占用内存大小均为32bit,在64位虚拟机中,占用的内存大小均为64bit。synchronized锁的信息,就存在Mark Word区域里。

你可能感兴趣的:(java,锁)