Java并发之线程八锁

Java并发之线程八锁,第1张

Java并发之线程八锁 一、引入

先了解什么是synchronized
不加 synchronzied 的方法就好比不遵守规则的人,不去老实排队(好比翻窗户进去的),记住一点,synchronized不是锁住了方法,而是锁住了使用了该方法的类对象或者对象实例,如:
1. 锁住对象实例:

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

2. 锁住类对象:

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

线程八锁的重点:

非静态方法的默认锁是this,静态方法的默认锁是class某一时刻内,只能有一个线程有锁,无论几个方法同一个类对象中的静态方法和非静态方法上锁,即对象实例上锁和类对象上锁,之间不会冲突不同对象实例间非静态方法执行不会冲突,非静态方法属于实例不同对象实例间静态方法执行会冲突,静态方法属于类 二、“八锁” 1. 对象实例:

情况1:12 或 21

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:对象实例
两个线程是对同一个实例对象上锁,a()方法或b()方法谁都可能先执行,先执行的会上锁,后面线程得等前一个线程结束才可以执行,通准确来说是同步,通俗讲是串行

情况2:1s后12,或 2 1s后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:对象实例
两个线程是对同一个实例对象上锁,a()方法的sleep并不是线程阻塞,是这个线程在运行中模拟有这么一段处理时间,a()方法或b()方法谁都可能先执行,先执行的会上锁,后面线程得等前一个线程结束才可以执行

情况3:3 1s 12 或 23 1s 1 或 32 1s 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:3个线程
锁:对象实例
a()方法和b()方法是对同一个实例对象上锁,两者不能并行运行,只能串行执行,c()方法没有锁,a()方法或b()运行时不影响c()方法并行运行,反过来c()方法运行a()和b()方法依旧可以运行
通过并行运行可以得出,最先输出的只能是2或3,因为a()方法可以先执行,但不会先输出1,如果对哪个方法先执行有疑虑,我可以告诉你,哪个方法都可以先执行,只是只能通过输出来看

情况4:2 1s 后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:对象实例
两个线程是对不同实例对象上锁,线程之间不会影响,可以并行执行,但b()方法比a()更早输出

2. 对象实例和类对象混合:

情况1:2 1s 后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:对象实例和类对象
引入那里我已经给大家补了,a()上的锁是类对象,b()方法上的锁是实例对象,即重点第三点,两者是独立执行,谁都不会阻塞,因此,b()方法输出比a()更快

情况2:1s 后12, 或 2 1s后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:类对象
两个线程是对同一个类对象上锁,先执行的上锁,后面的阻塞,因此先执行第一个线程,第二个才可以执行,结果会出现两种

情况3:2 1s 后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:对象实例和类对象
两个线程执行的是不同对象的方法,非静态方法和静态方法(类和实例)、非静态方法和非静态方法(实例与实例,两个不同实例)之间不会冲突,可以并行运行,并行是相对于多核的,单核那叫时间片轮询执行,看起来也像是并行,不过是内核在做上下文切换,影响的是性能

情况4:1s 后12, 或 2 1s后 1

@Slf4j(topic = "c.Number")
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();
}

解释:
线程数:2个线程
锁:类对象
与情况二类似,上锁的根本在于同一个类,对不同实例是没有毛钱关系,所以这里也会有上锁,会发生阻塞

三、总结

线程八锁,实际是总结出来也就是,上锁【类、实例】和线程执行方法【是否同实例】的划分,而增加sleep是为了能够更好的展示效果,能够更好去理解线程。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5717011.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存