多线程synchronized(锁)
多线程 synchronized
将并行改串行,多个线程同时开始,执行同一段加锁的代码,那么这段代码在任何时间仅能由一个线程执行,且这个线程在执行完这段代码中的内容后才会释放锁,执行期间其他线程无法进来捣乱执行(因为未获取到锁),在这个线程未释放锁前,其他线程只能阻塞。
举个形象的例子便于理解
几个人(线程)同时需要用厕所(被锁的代码),但是坑位只有一个,那么任何时间都只能是这些人中的某一个人使用唯一的坑位,并且在他丢炸弹的时候,其他人不能强行进来抢用坑位。那么这就需要一个标识表示坑位正在被使用,就是厕所门(锁对象),门开着,所有人都可以竞争使用唯一的坑位,门关上,坑位正在被某人使用(运行状态),其他人只能在外等候(阻塞状态),等候的人什么也做不了(不执行任务)。
类锁
同一个类,不管多少个实例,锁始终生效。
-
锁static修饰的方法
public class ClassSync implements Runnable{ public static synchronized void sync(){ for (int i = 0; i < 4; i++) { try { TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+i); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
Main
public static void main(String[] args) throws InterruptedException { new Thread(()->{ ClassSync.sync(); }, "_a").start(); new Thread(()->{ ClassSync.sync(); }, "_b").start(); }
打印结果
_a0 _a1 _a2 _a3 _b0 _b1 _b2 _b3
你可以再试试去掉
synchronized
,比较一下两者输出结果的差异。 -
用代码块锁类
public class ClassSync implements Runnable{ @Override public void run() { synchronized (ClassSync.class){//锁此类 for (int i = 0; i < 4; i++) { try { TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+i); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } }
Main
public static void main(String[] args) throws InterruptedException { ClassSync classSync = new ClassSync() new Thread(classSync, "_a").start(); new Thread(classSync, "_b").start(); }
打印结果
_a0 _a1 _a2 _a3 _b0 _b1 _b2 _b3
你可以再试试去掉
synchronized (ClassSync.class){}
代码块,比较一下两者输出结果的差异。
对象锁
锁的是对象,也就是实例,对象锁仅在多个线程操作同一个类时才生效。
public class ClassSync implements Runnable{
@Override
public void run() {
synchronized (this){
for (int i = 0; i < 4; i++) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
Main
public static void main(String[] args) throws InterruptedException {
ClassSync a = new ClassSync();
new Thread(a,"_a").start();
new Thread(a,"_b").start();
}
并不限定必须使用this,this指向的是类实例,也就是ClassSync的实例a,还可以写成其他的对象(是对象!实例化的对象!!),比如一个字符串,一个object对象等。比如下面的例子,我用了一个名为lock
的字符串,仍然可以保证锁生效。
public class ClassSync implements Runnable{
private String lock = "lock";
@Override
public void run() {
synchronized (lock){
for (int i = 0; i < 4; i++) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
若定义多个ClassSync
类对象,线程操作的对象相互不同,对象锁将不生效
public static void main(String[] args) throws InterruptedException {
ClassSync a = new ClassSync();
ClassSync b = new ClassSync();
new Thread(a,"_a").start();
new Thread(b,"_b").start();
}
执行结果
_a0
_b0
_a1
_b1
_a2
_b2
本文来自博客园,作者:勤匠,转载请注明原文链接:https://www.cnblogs.com/JarryShu/articles/18183347
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现