美文网首页JAVA
9.锁相关和synchronized关键字

9.锁相关和synchronized关键字

作者: 强某某 | 来源:发表于2020-03-03 15:11 被阅读0次
  1. JAVA中锁的概念
  • 自旋锁:例如为了不放弃CPU执行事件,循环的使用CAS技术对数据尝试进行更新,直至成功(乐观锁的一种)
  • 悲观锁:假定会发生并发冲突,同步所有对数据的相关操作,从读取数据就开始上锁(例如synchronized)
  • 乐观锁:假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改后重试修改
  • 独享锁(写): 给资源加上写锁,该线程可以修改资源,其他线程不能再加锁,也就代表着只有该线程能读写,其他线程读写都不行;(单写)
  • 共享锁(读):给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁;(多读)
  • 可重入锁、不可重入锁:线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码
  • 公平锁、非公平锁:争抢锁的顺序,如果是按先来后到,则为公平
  1. 同步关键字synchronized
    属于最基本的线程通信机制,基于对象监视器实现的。Java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁。
    一次只有一个线程可以锁定监视器,试图锁定该监视器的任何其他线程都会被阻塞,直到它们可以获得该监视器上的锁定为止。
  • 特性:可重入、独享、悲观锁

  • 锁的范围:类锁、对象锁、锁消除、锁粗化

  • 提示:同步关键字,不仅是实现同步,根据JMM规定还能保证可见性(读取最新主内存数据,结束后写入主内存)

public class ObjectSyncDemo {

    public synchronized void test() {
        try {
            System.out.println(Thread.currentThread()+"开始执行");
            Thread.sleep(3000L);
            System.out.println(Thread.currentThread()+"执行结束");
        } catch (Exception e) {

        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            new ObjectSyncDemo().test();
        }).start();
        Thread.sleep(1000L);
        new Thread(()->{
            new ObjectSyncDemo().test();
        }).start();
    }
}
Thread[Thread-0,5,main]开始执行
Thread[Thread-1,5,main]开始执行
Thread[Thread-0,5,main]执行结束
Thread[Thread-1,5,main]执行结束

此时结果输出如上:因为synchronized此时是对象锁,new ObjectSyncDemo就是新对象,两者互不影响

public class ObjectSyncDemo {

    public synchronized static void test() {
        try {
            System.out.println(Thread.currentThread()+"开始执行");
            Thread.sleep(3000L);
            System.out.println(Thread.currentThread()+"执行结束");
        } catch (Exception e) {

        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            new ObjectSyncDemo().test();
        }).start();
        Thread.sleep(1000L);
        new Thread(()->{
            new ObjectSyncDemo().test();
        }).start();
    }
}
Thread[Thread-0,5,main]开始执行
Thread[Thread-0,5,main]执行结束
Thread[Thread-1,5,main]开始执行
Thread[Thread-1,5,main]执行结束

此时static已经是类锁了,即两个线程是同一把锁,所以才依次执行

> 此时也是对象锁,不会依次执行
public class ObjectSyncDemo {

    public void test() {
        try {
            synchronized (this) {
                System.out.println(Thread.currentThread() + "开始执行");
                Thread.sleep(3000L);
                System.out.println(Thread.currentThread() + "执行结束");
            }
        } catch (Exception e) {

        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            new ObjectSyncDemo().test();
        }).start();
        Thread.sleep(1000L);
        new Thread(() -> {
            new ObjectSyncDemo().test();
        }).start();
    }
}
> 此时是类锁,依次执行
public class ObjectSyncDemo {
    // static Object o=new Object();
    public void test() {
        try {
            synchronized (ObjectSyncDemo.class) {
            // synchronized (0) {  此时也是类级别的锁,会依次执行
                System.out.println(Thread.currentThread() + "开始执行");
                Thread.sleep(3000L);
                System.out.println(Thread.currentThread() + "执行结束");
            }
        } catch (Exception e) {

        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            new ObjectSyncDemo().test();
        }).start();
        Thread.sleep(1000L);
        new Thread(() -> {
            new ObjectSyncDemo().test();
        }).start();
    }
}
  1. 可重入锁
public class ObjectSyncDemo {
    public synchronized void test(Object arg) {
        System.out.println(Thread.currentThread()+"开始执行"+arg);
        if (arg==null) {
            test(new Object());
        }
        System.out.println(Thread.currentThread()+"执行结束"+arg);
    }

    public static void main(String[] args) throws InterruptedException {
            new ObjectSyncDemo().test(null);
    }
}

Thread[main,5,main]开始执行null
Thread[main,5,main]开始执行java.lang.Object@16d3586
Thread[main,5,main]执行结束java.lang.Object@16d3586
Thread[main,5,main]执行结束null
  1. 锁粗化
    所谓锁粗化:就是jit在运行时动态的在不影响结果的情况下扩大锁的范围从而优化性能
//锁粗化(运行时jit编译优化)
//jit编译后的汇编内容,jitwatch可视化工具查看
public class ObjectSyncDemo {
    int i;
    public synchronized void test(Object arg) {
        synchronized (this) {
            i++;
        }
        synchronized (this) {
            i++;
        }
        //再jit判断运行次数,从而局部优化代码,如上一万次,会被优化成如下
//        synchronized (this) {
//            i++;
//            i++;
//        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100000; i++) {
            new ObjectSyncDemo().test(null);
        }
    }
}
  1. 锁消除
import javax.management.ObjectName;

public class ObjectSyncDemo {
    public void test3(Object arg) {
        StringBuilder sb=new StringBuilder();
        sb.append("a");
        sb.append("b");
        sb.append("c");
        System.out.println(arg.toString());
    }
    public void test2(Object arg) {
        String a="a";
        String c="c";
        System.out.println(a+arg+c);
    }
    public void test1(Object arg) {
        //jit优化,消除锁,因为StringBuffer是线程安全的,append点击去看,都有synchronized
        //锁消除之后,就会发现锁被取消了,没有锁了;之所以如此也是为了提高性能,因为循环次数太多了
        StringBuffer stringBuffer=new StringBuffer();
        stringBuffer.append("a");
        stringBuffer.append(arg);
        stringBuffer.append("c");
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000000; i++) {
            new ObjectSyncDemo().test1("123");
        }
    }
}
  1. 同步关键字加锁原理


    3.png
  • 偏向锁到轻量级锁


    1.png
  • 轻量级锁


    4.png
  • 重量级锁-监视器(monitor)


    2.png

相关文章

网友评论

    本文标题:9.锁相关和synchronized关键字

    本文链接:https://www.haomeiwen.com/subject/wmchlhtx.html