摘要:别的线程想要拿到锁,就必须等待当前线程执行完成并释放锁,才能再次给对象加锁,达到线程同步互斥作用。为了提升线程执行效率,就要最小化同步代码块,最小化锁粒度。
在java中处理线程并发问题,可以简单的加上synchronized,可以在方法或方法内的代码块添加,那现在的问题是,synchronized是锁住了方法还是代码块还是实例对象?
加在方法上:
class Sync { public synchronized void test() { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } } public class Main { public static void main(String[] args) { for (int i = 0; i < 3; i++) { Thread thread = new MyThread(); thread.start(); } } }
运行结果: test开始.. test开始.. test开始.. test结束.. test结束.. test结束
可以看到,上面启了3个线程,每个线程实例化一个Sync并调用其方法,所以这里synchronized没有作用,因为线程都加了各自的同步锁,无互斥。
若把test方法上加上static,则运行结果如下:
test开始.. test结束.. test开始.. test结束.. test开始.. test结束
因为此时,3个线程的同步锁是Sync类对象而不是类实例。
public static synchronized void test() { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); }
注:线程sleep时,并不会释放锁.
接下来,把synchronized加到this上,如下:
public void test() { synchronized(this) { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } }
运行结果:test开始.. test开始.. test开始.. test结束.. test结束.. test结束
同样的道理,这里的同步锁是自各的对象实例,3个线程互不影响,没有互斥作用
由此得知,synchronized在方法上锁的是对象实例,在代码块里锁的是括号里的对象。别的线程想要拿到锁,就必须等待当前线程执行完成并释放锁,才能再次给对象加锁,达到线程同步互斥作用。
为了提升线程执行效率,就要最小化同步代码块,最小化锁粒度。
上面使用static实现了线程互斥,其实也可以用同一个对象来实现线程互斥,如下:
class MyThread extends Thread { private Sync sync; public MyThread(Sync sync) { this.sync = sync; } public void run() { sync.test(); } } public class Main { public static void main(String[] args) { Sync sync = new Sync(); for (int i = 0; i < 3; i++) { Thread thread = new MyThread(sync); thread.start(); } } }
运行结果:test开始.. test结束.. test开始.. test结束.. test开始.. test结束
可以看到,线程同步互斥了
更好的做法是,直接锁住这个对象的class对象,与static相同,如下:
class Sync { public void test() { synchronized (Sync.class) { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } }
运行结果:test开始.. test结束.. test开始.. test结束.. test开始.. test结束
可以看到,线程仍然同步互斥
综上,若需要同步锁,尽量最小化同步块。
学习交流,欢迎加群:64691032
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76983.html
摘要:并发编程的挑战并发编程的目的是为了让程序运行的更快,但是,并不是启动更多的线程就能让程序最大限度的并发执行。的实现原理与应用在多线程并发编程中一直是元老级角色,很多人都会称呼它为重量级锁。 并发编程的挑战 并发编程的目的是为了让程序运行的更快,但是,并不是启动更多的线程就能让程序最大限度的并发执行。如果希望通过多线程执行任务让程序运行的更快,会面临非常多的挑战:(1)上下文切换(2)死...
摘要:分布式锁实现方式前言目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于数据库实现分布式锁基于缓存等实现分布式锁基于实现分布式锁。 前言 分布式锁,是控制分布式系统之间同步访问共享资源的一种方式 在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥...
摘要:分布式锁实现方式前言目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于数据库实现分布式锁基于缓存等实现分布式锁基于实现分布式锁。 前言 分布式锁,是控制分布式系统之间同步访问共享资源的一种方式 在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥...
摘要:如问到是否使用某框架,实际是是问该框架的使用场景,有什么特点,和同类可框架对比一系列的问题。这两个方向的区分点在于工作方向的侧重点不同。 [TOC] 这是一份来自哔哩哔哩的Java面试Java面试 32个核心必考点完全解析(完) 课程预习 1.1 课程内容分为三个模块 基础模块: 技术岗位与面试 计算机基础 JVM原理 多线程 设计模式 数据结构与算法 应用模块: 常用工具集 ...
摘要:而导致这个问题的原因是线程并行执行操作并不是原子的,存在线程安全问题。如果已经有线程持有了锁,那这个线程会独占锁,直到锁释放完毕之前,其他线程都会被阻塞。当锁处于重量级锁状态,其他线程尝试获取锁时,都会被阻塞,也就是状态。 1. 什么时候需要用SynchronizedSynchronized主要作用是在多个线程操作共享数据的时候,保证对共享数据访问的线程安全性。比如两个线程对于i这个共...
阅读 2135·2021-11-18 10:02
阅读 3440·2021-11-15 11:36
阅读 1068·2019-08-30 14:03
阅读 686·2019-08-30 11:08
阅读 2731·2019-08-29 13:20
阅读 3249·2019-08-29 12:34
阅读 1342·2019-08-28 18:30
阅读 1560·2019-08-26 13:34