JUC:synchronized详解与线程八锁问题解析

本文分析了`synchronized`在Java中的应用,介绍了对象锁与类锁的区别,以及八种典型线程同步场景:实例方法、静态方法和对象/类锁的交互作用。
摘要由CSDN通过智能技术生成

synchronized

synchronized俗称对象锁,只有获取了锁的线程才能执行被锁住的代码。

有且只有一个线程能获取对象锁。既可以让线程之间互斥访问被锁住的对象。

即使线程切换,没有锁也运行不了临界区中的代码,这样就可以保证读写的原子性,那么就一定正确。

代码示例

@Slf4j(topic = "c.Test3")
public class st3 {
    static int count = 0;
    static Object lock = new Object();
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (lock) {
                    count++;
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (lock){
                    count--;
                }
            }
        }, "t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}",count);
    }
}

在这里插入图片描述

面向对象改进:

@Slf4j(topic = "c.Test3")
public class st3 {
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new Lock();
        Thread t1 = new Thread(() -> {
            for (int j = 0; j < 5000; j++) {
                lock.incr();
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int j = 0; j < 5000; j++) {
                lock.decr();
            }
        }, "t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        log.debug("count: {}" , lock.getCount());
    }

}

class Lock{
    private int count = 0;

    public void incr() {
        synchronized(this) {
            count++;
        }
    }

    public void decr() {
        synchronized (this) {
            count--;
        }
    }

    public int getCount() {
        return count;
    }
}

在这里插入图片描述

一样的只不过,在类方法里调用,锁的是当前对象this。

方法上加synchronized

加在普通方法上是对象锁,加载静态方法上是类锁。
而不加锁的方法不受任何影响。

class Test{
    public synchronized void test() {

    }
}
等价于
class Test{
    public void test() {
        synchronized(this) {

        }
    }
}
class Test{
    public synchronized static void test() {
        
    }
}
等价于
class Test{
    public static void test() {
        synchronized(Test.class) {

        }
    }
}

注意:不要有误区,不要认为类锁被锁后其类对应的所有对象锁也不能再执行,类锁锁住的是类对象,也是一个对象而已,也就是Class c = xx.getClass()这个对象。

所以我认为没必要区分什么锁类锁对象啥的,都是锁一个对象。只不过一个锁的该类的对象,一个锁的该类的Class对象。不过我们通常将锁一个类叫做类锁而已。

线程八锁

"线程八锁"通常是指Java中关于多线程同步的八种情况,这些情况是基于对象锁的不同组合而产生的。这些情况包括对实例方法和静态方法的访问,以及对普通对象和Class对象的访问。
对于非静态同步方法,锁的是当前实例对象。
对于静态同步方法,锁的是当前类的Class对象。
对于同步方法块,锁的是括号里配置的对象。

下面我们就来全面解析吧。

No.1

class Number{
    public synchronized void a() {
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}

a、b锁对象,互斥,执行顺序随机。
答案:
1、2 或
2、1

No.2

class Number{
    public synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}

a、b锁对象、互斥,执行顺序随机。
答案:1s、1、2 或
2、1s、1

No.3

class Number{
    public synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
    public void c() {
        log.debug("3");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
    new Thread(()->{ n1.c(); }).start();
}

a、b锁对象,c普通方法,同一对象的a、b互斥、普通方法不受影响,随时可以执行。
答案:3、2、1s、1 或
3、1s、1、2 或
2、3、1s、1

No.4

class Number{
    public synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    Number n2 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n2.b(); }).start();
}

a、b锁对象,但是调用对象不同,互不影响。
答案:
2、1s、1

No.5

class Number{
    public static synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}

a锁对象、b锁类(Class对象),互不影响。
答案:
2、1s、1

No.6

class Number{
    public static synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public static synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}

a、b锁类,互斥,执行顺序随机。
答案:
1s、1、2 或
2、1s、1

No.7

class Number{
    public static synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    Number n2 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n2.b(); }).start();
}

a锁类、b锁对象,但是调用对象和方法都不同,互不影响。
答案:
2、1s、1

No.8

class Number{
    public static synchronized void a() {
        sleep(1);
        log.debug("1");
    }
    public static synchronized void b() {
        log.debug("2");
    }
}

public static void main(String[] args) {
    Number n1 = new Number();
    Number n2 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n2.b(); }).start();
}

a、b都是锁类、虽然是不同对象调用,但是他俩锁的类,互斥,执行顺序随机。
答案:
1s、1、2
2、1s、1

  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cosmoshhhyyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值