先了解什么是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()更早输出
情况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是为了能够更好的展示效果,能够更好去理解线程。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)