这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!!
沉下去,再浮上来
,我想我们会变的不一样的。讲Lock接口之前先让我们一起来回顾一下Synchronized关键字吧。
我想我们学Java开发这么久,不可能还有那个小伙伴没有用过synchronized
封面是庞大的朋友圈贡献的
JUC系列
一、synchronized 作用范围:
synchronized 是 Java 中的关键字,是一种同步锁。它修饰的对象有以下几种:
-
修饰某一处代码块,被修饰的代码块称为同步语句块。作用范围就是
{}
之间。作用的对象是调用这个代码块的对象。synchronized (this){ System.out.println("同步代码块 "); }
-
修饰在方法上,被修饰的方法就称为同步方法。作用范围则是整个方法。作用的对象则是调用这个方法的对象。
public synchronized void sale() { }
注
:1)synchronized 关键字不能被继承,如果父类中某方法使用了synchronized 关键字,字类又正巧覆盖了,此时,字类默认情况下是不同步的,必须显示的在子类的方法上加上才可。当然,如果在字类中调用父类中的同步方法,这样虽然字类并没有同步方法,但子类调用父类的同步方法,子类方法也相当同步了。 -
. 修饰某个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象。
public static synchronized void test(){ }
-
修饰某个类,其作用的范围是 synchronized 后面括号括起来的部分,作用的对象是这个类的所有对象。
class Ticket { public void sale() { synchronized (Ticket.class) { } } }
二、案例:
最后:我们拿synchronized 写一下多线程中的卖票的经典案例:
public class SynchronizedDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "C").start();
}
}
class Ticket {
//票数
private int number = 30;
//操作方法:卖票
public synchronized void sale() {
//判断:是否有票
if (number > 0) {
System.out.println(Thread.currentThread().getName() + " : " + (number--) + " " + number);
}
}
}
三、总结:
synchronized 的同步效率非常低,因为一个如果某一块代码被synchronized 修饰了,当某一个线程进入了synchronized 修饰的代码块,那么其他线程只能一直等待,等待获取锁的线程释放锁,才能进入再次进入同步代码块。
获取锁的线程释放锁的情况只有两种:
- 正常执行完,然后释放锁。
- 执行过程中,发生异常,JVM让线程自动释放锁。
那么你试想一个如果获取到锁的这个线程,由于一些等待IO原因或其他原因被堵住了,但是又不能释放锁,其他线程就只能在synchronized的门口看着啦,你想一下这个效率吧,出现一次,可能就把人心态玩没啦哈。😂
因此非常需要有一种机制能够不让等待的线程一直无限期的等待下去,比如改成等待一段时间或者响应中断,该怎么做呢?
我们可以通过Lock来做这件事情。
四、自言自语
关于Lock的知识点就在下一篇文章中哦。
最近又开始了JUC的学习,感觉Java内容真的很多,但是为了能够走的更远,还是觉得应该需要打牢一下基础。
最近在持续更新中,如果你觉得对你有所帮助,也感兴趣的话,关注我吧,让我们一起学习,一起讨论吧。
你好,我是博主宁在春
,Java学习路上的一颗小小的种子,也希望有一天能扎根长成苍天大树。
希望与君共勉
😁
待我们,别时相见时,都已有所成。