【185期】面试官:你能说说 Synchronized实现对象锁的两种方式以及它的原理吗?
阅读本文大概需要 4.5 分钟。
来自:blog.csdn.net/x541211190/article/details/106179245
一.同步代码块锁
count
,各自执行1万次count++
,验证结果是否等于2万,而不会出现小于2万的情况。public class SynchronizeCodeBlockLock implements Runnable {
private static SynchronizeCodeBlockLock instance = new SynchronizeCodeBlockLock();
private static int count = 0;
@Override
public void run() {
method();
}
private void method() {
// 关键:同步代码块的方式,操作同一变量,达到线程安全的效果
synchronized (this) {
System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
for (int i = 0; i < 10000; i++) {
count++;
}
System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
// 若有线程如果还在活动,则不执行下一步(等同于thread.join()方法)
}
System.out.println("期待结果:20000,实际结果:" + count);
}
}
线程名:Thread-0,运行开始
线程:Thread-0,运行结束
线程名:Thread-1,运行开始
线程:Thread-1,运行结束
期待结果:20000,实际结果:20000
synchronized
关键字后,线程Thread-0先执行,等到其结束后,Thread-1才开始执行。如果不使用synchronized
关键字,执行结果可能会是Thread-0和Thread-1几乎同时执行,几乎同时运行结束。这就说明使用了synchronized
关键字后,将多个线程的并行,变为了串行。二.方法锁
public class MethodLock implements Runnable {
private static MethodLock instance = new MethodLock();
@Override
public void run() {
method();
}
//关键:synchronized可以保证此方法被顺序执行,线程1执行完4秒钟后,线程2再执行4秒。不加synchronized,线程1和线程2将同时执行
private synchronized void method() {
System.out.println("线程:" + Thread.currentThread().getName() + ",运行开始");
try {
//模拟执行一段操作,耗时4秒钟
Thread.sleep(4000);
System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 模拟:同一个对象下,两个线程,同步执行一个方法(串行执行则为线程安全,并行执行,则为线程不安全,)
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
}
System.out.println("测试结束");
}
}
线程:Thread-0,运行开始
线程:Thread-0,运行结束
线程:Thread-1,运行开始
线程:Thread-1,运行结束
测试结束
三.synchronized关键字,是怎么保证线程安全的呢?
synchronized
代码块前时,会自动获取到监视器锁,此时其他线程在访问synchronized
代码块时,就会被堵塞挂起(被拒之门外的意思)。拿到锁的线程会在执行完成、或者抛出异常、或者调用wait系列方法时释放该锁。其他线程只能等待锁被释放后才能获取该锁。synchronized
关键字将代码块中代码由并行
转变成了串行
,这样就保证了代码被顺序执行。四.synchronized在内存层面,是如何实现加锁和释放锁的?
进入
synchronized
代码块时,会将代码块内用到的变量从该线程的工作内存中清除,转而从主内存中获取。退出
synchronized
代码块时,会将代码块内用到的变量的修改,刷新到主内存中。
synchronized
解决共享变量内存可见性
的原理。关于synchronized
的性质(可见性、可重入性),我会在后续其他文章中详细解释。五.synchronized将线程的并行处理转为串行处理,有什么缺点?
synchronized
将并行改为串行,当然会影响程序的执行效率,执行速度会受到影响。其次,synchronized
操作线程的堵塞,也就是由操作系统控制CPU的内核进行上下文的切换,这个切换本身也是耗时的。所以使用synchronized
关键字会降低程序的运行效率。六. 使用Synchronized关键字需要注意什么?
七.总结
synchronized (共享变量) {
//需要同步的代码
}
private synchronized void method() {
//需要同步的代码
}
推荐阅读:
【182期】SpringCloud常见面试题(2020最新版)
微信扫描二维码,关注我的公众号
朕已阅