java锁学习(二)

Wesley13
• 阅读 930

类锁

类锁 !!!! java类有很多对象 ,但是只有一个class对象 !!!!

所以,类锁,就是针对当前类的Class对象的锁

类锁同一时刻只能被一个对象获取

  1. synchronized放在static方法上(静态锁)
  2. synchronized放在class对象上

静态锁

class SyncClassStatic implements Runnable {
    @Override
    public void run() {
        method();
    }

    public static synchronized void method() {
        System.out.println("我是类锁中静态锁");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"运行结束");
    }
}
result:
我是类锁中静态锁
Thread-6运行结束
我是类锁中静态锁
Thread-7运行结束
类锁,静态锁运行完毕

class对象锁

class SyncClassObj implements Runnable{
    @Override
    public void run() {
        method();
    }

    private void method(){
        synchronized (SyncClassObj.class) {
            System.out.println("我是类锁中class对象锁");
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"运行结束");
        }
    }
}
result:
我是类锁中class对象锁
Thread-8运行结束
我是类锁中class对象锁
Thread-9运行结束
类锁,class对象运行完毕

常见场景和问题

  1. 两个线程同时访问一个对象的同步方法会怎样?

    依次执行(锁住的是同一个对象)

  2. 两个线程访问的是两个对象的同步方法又会怎样?

    随机执行(锁住的是不同的对象)

  3. 两个线程访问的是synchronized的静态方法会怎样?

    依次执行(锁住的是同一个类)

  4. 同时访问同步方法与非同步方法会怎样?

    只锁加了synchronized的方法,其他方法不会收到影响

    class SyncObjLock implements Runnable {

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")) {
            syncMethod();
        }else{
            asyncMethod();
        }
    }
    
    private synchronized void syncMethod()
    {
        System.out.println("我被锁了");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println(Thread.currentThread().getName()+"运行结束");
    }
    
    private void asyncMethod()
    {
        System.out.println("我没被锁");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println(Thread.currentThread().getName()+"运行结束");
    }
    

    } 同时开始,同时结束: 我被锁了 我没被锁 Thread-0运行结束 Thread-1运行结束

  5. 访问同一个对象的不同的普通同步方法会怎样?

    class SyncDiff implements Runnable{ @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")) { syncMethod1(); }else{ syncMethod2(); } } private synchronized void syncMethod1() { System.out.println("我被锁了,我是方法1"); try{ Thread.sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); } private synchronized void syncMethod2() { System.out.println("我被锁了,我是方法2"); try{ Thread.sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); } } 同时开始,同时结束: 我被锁了 我没被锁 Thread-0运行结束 Thread-1运行结束

  6. 同时访问静态sync和非静态sync方法

    class SyncStaticOrNo implements Runnable { @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")) { syncMethod1(); }else{ syncMethod2(); } } private synchronized void syncMethod1() { System.out.println("我被对象锁"); try{ Thread.sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); } private static synchronized void syncMethod2() { System.out.println("我是类锁"); try{ Thread.sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); } } 同时开始,同时结束: 我被锁了 我没被锁 Thread-0运行结束 Thread-1运行结束

  7. 方法抛出异常后,会释放锁吗?

会,jvm帮我们释放了

class SyncExc implements Runnable{


    @Override
    public void run() {
            method1();
    }

    private synchronized void method1()
    {
        System.out.println(Thread.currentThread().getName()+"开始");
        try{
            Thread.sleep(3000);
        }catch (Exception e) {
            e.printStackTrace();
        }
        throw new RuntimeException("");
//        System.out.println("运行结束");
    }

}


Thread-0开始
Exception in thread "Thread-0" java.lang.RuntimeException: 
    at Thread.SyncExc.method1(SynchronizedObject.java:187)
    at Thread.SyncExc.run(SynchronizedObject.java:176)
    at java.lang.Thread.run(Thread.java:748)
Thread-1开始
Exception in thread "Thread-1" java.lang.RuntimeException: 
    at Thread.SyncExc.method1(SynchronizedObject.java:187)
    at Thread.SyncExc.run(SynchronizedObject.java:176)
    at java.lang.Thread.run(Thread.java:748)

锁的使用场景及分析

整个系统全局同步用类锁,局部锁用对象锁

对比下,就像一样,锁的范围越大,性能自然越低(粒度:类锁>对象锁 性能:类锁<对象锁)

点赞
收藏
评论区
推荐文章
执键写春秋 执键写春秋
3年前
notifyAll唤醒线程的范围?
今天看到开源中国上有这样一个问答:假设我有两个对象锁,对象A锁有5个线程在等待,对象B锁有3个线程在等待,对象A锁中的线程执行完,这时调用notifyAll,是唤醒了对象AB两个锁的全部的等待线程还是只唤醒了A锁的5个线程?1.方法文档解释通过看该方法文档的解释,可以得出下面结论:notifyAll()中All的含义是所有的线程,而不是所有的锁,只能唤
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
synchronize底层原理
1、普通同步方法,锁是当前实例对象2、静态同步方法,锁是当前类的class对象3、同步方法块,锁是括号里面的对象synchronize底层原理:Java虚拟机中的同步(Synchronization)基于进入和退出Monitor对象实现,无论是显式同步(有明确的monitorenter和monitorexit指令,即同步代
Wesley13 Wesley13
3年前
JAVA对象布局之对象头(Object Header)
由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能。在学习并发编程知识synchronized时,我们总是难以理解其实现原理,因为偏向锁、轻量级锁、重量级锁都涉及到对象头,所以了解java对象头是我们深入了解synchronized的前提条件,以下我们使用64
Wesley13 Wesley13
3年前
Java并发编程之Synchronized
引子目前在Java中存在两种锁机制:synchronized和Lock,今天我们先来介绍一下synchronizedsynchronized可以保证方法或代码块在运行时,同一时刻只有一个线程可以进入到临界区,同时它还保证了共享变量的内存可见性。用法Java中的每个对象都可以作为锁。每一个Object类及其子类
Wesley13 Wesley13
3年前
Java学习笔记7
lock接口实现类ReentrantLock我们可以用lock对象,来对临界资源加锁,只有获得lock对象才能访问临界资源,如果没有获得lock对象,就会进入lock对象的锁池。trylock()方法会返回布尔值,这个方法是用来判断这个锁对象是不是已经被线程获取,如果返回值为true,则会直接获得这个锁对象,如果返回false,线程不会阻塞还会继
Wesley13 Wesley13
3年前
Java多线程进阶干货(2)
问题1:子类可以调用父类的同步方法吗?/    一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,  再次申请时,仍然会得到该对象的锁,也就是说synchronized获得的锁是可重入的   这里是继承中有可能发生的情形,子类调用父类的同步方法 /public class Test09 {    sy
Wesley13 Wesley13
3年前
Java多线程锁释放
Java多线程运行环境中,在哪些情况下会使对象锁释放?由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:(1)执行完同步代码块,就会释放锁。(synchronized)(2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exc
Wesley13 Wesley13
3年前
Java线程中的同步
!(https://static.oschina.net/uploads/space/2018/0207/164552_Gl6r_3643112.jpg)1、对象与锁每一个Object类及其子类的实例都拥有一个锁。其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁。单独的成员变量是不能被标明为同步
Wesley13 Wesley13
3年前
Java并发编程总结(一)Syncronized解析
Syncronized解析作用:(1)确保线程互斥的访问同步代码(2)保证共享变量的修改能够及时可见(3)有效解决重排序问题。用法:(1)修饰普通方法(锁是当前实例对象)(2)修饰静态方法(锁是当前对象的Class对象)(3)修饰代码块(锁是Synchonized括号里配置的