本人很少原创技术文章(其他文章页很少),一般都是看别人文章写得就转发一下,但是关于多线程这块我一直都没有找到能说中要害又通俗易懂的文章,本人不是什么大牛,但在java线程锁这一块觉得自己理解的还算正确吧,本着知识共享的精神,今天我就试着把这一块说说,用的都是最通俗的语言,最简单的代码(命名没有做到见文识意,应该批评),希望能帮助困惑中的人解脱出来,如果我理解错了,那么也请大牛们帮我解脱出来,无论如何,要么我受益,要么大家受益。
首先我说一下一部分人的错误理解,网上讲多线程的文章很多,但多数文章看完之后会留下这么一个印象:一个synchronized 关键字会锁住一段代码,被一个synchronized关键字控制的代码块同时只允许一个线程进入;
其实在逻辑上这句话是对的,但他把重点放在了代码块上,这就不对了,这样容易让人进入一个误区,那就是一个synchronized关键字控制区内同时只允许进入一个线程的。哪里错了呢?错就错在一个线程进入一个synchronized区后锁住的不只是那一个synchronized之后的代码块,其他synchronized之后的代码也可能已经被锁住了,因为线程锁的重点不在synchronized关键字和其后的{}的范围,而是synchronized(obj)括号里面的参数obj,这个参数才是应该关注的焦点。
我们可以把synchronized看成一个门,synchronized(obj)里面的obj就是钥匙,线程就是要进门的人,人进门前需要先拿钥匙开门,然后带着钥匙进去,进去后锁门不让别人进,出来后再锁上门,然后把钥匙放下,之后另一个人才能再拿上钥匙进出。多个synchronized(obj)就是多扇门,如果它们需要的是同一把钥匙,那么一旦一个人拿着钥匙进入其中一个门,就会导致其他人无法拿到钥匙,也就无法打开所有需要这把钥匙的门,而不只是刚才进入的那个门,拿着钥匙的人可以在多个门里来回进出,其他人就只能在外面等着,千万不要认为拿着钥匙的人进入了一个门就只锁住了那一个门,总结一句话:只要他们用的锁一样,不管代码块在什么位置,都会互相影响。如果这个比方还不够清楚下面我们直接用代码测试吧。
先创建一个测试类,有两个加锁的静态方法:
public class Test1 {
/** 注意这样的静态方法默认是以Test1.class作为钥匙的 相当于synchronized(Test1.class)**/
public synchronized static void staticMethod1(){
//如果我在这里睡觉,那么Test1的staticMethod2别想睡觉,当然如果他先拿到钥匙的话就是他说了算了
System.out.println("Test1.staticMethod1 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test1.staticMethod1 睡醒了。。。");
}
/** 注意这样的静态方法默认是以Test1.class作为钥匙的 相当于synchronized(Test1.class)**/
public synchronized static void staticMethod2(){
//如果我在这里睡觉,那么Test1的staticMethod1别想睡觉,当然如果他先拿到钥匙的话就是他说了算了
System.out.println("Test1.staticMethod2 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test1.staticMethod2 睡醒了。。。");
}
}
下面再写两个线程类,分别调用上面类的两个方法:
public class MyThread1 extends Thread{
public void run(){
Test1.staticMethod1();
}
}
public class MyThread2 extends Thread{
public void run(){
Test1.staticMethod2();
}
}
好了测试一下吧,下面是测试代码,看官也可以先预测一下结果
public class ThreadTester {
public static void main(String[] args) {
//这里线程启动顺序无所谓,只要一个线程启动了另一线程就必须等待,这是要关注的
new MyThread1().start();
new MyThread2().start();
}
}
通过运行结果大家可以得出一个结论,那就是调用任意一个synchronized(Test1.class)的方法,会锁住所有带synchronized(Test1.class)的方法,因为他们需要的钥匙Test1.class被拿走了。
上面测试了synchronized方法,下面我们再测试一下synchronized(Test1.class)代码块,现在我们新建一个类:
public class Test2 {
public static void staticMethod1(){
synchronized(Test1.class){ //这里的钥匙是Test1.class
//如果我在这里睡觉,那么Test1的方法staticMethod1和staticMethod2都别想睡觉,当然如果他们先拿到钥匙的话就是你们说了算了
System.out.println("Test2.staticMethod1 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test2.staticMethod1 睡醒了");
}
}
}
这里,在Test1的外面有一个类Test2竟然有一个方法里面有一段代码用Test1.class作为钥匙,可怕的事情总是这样发生,一定要明白如果这里有什么阻塞的话其他线程调用Test1方法的线程也会被阻塞的
另外再补充一点
public class Test3 {
/** 注意这样的静态方法默认是以this作为钥匙的 相当于synchronized(this)**/
public synchronized void method1(){
}
}
这样的对象方法只有多个线程同时操作同一个对象时才会相互排斥,注意是“同一个对象”,多发生于单例模式;把一个对象传给两个线程做参数的情况也会形成锁竞争,但这种写法比较少见,例如下面情况:
public class MyThread4 extends Thread{
private Test3 t3;
public MyThread4(Test3 t3){
this.t3 = t3;
}
public void run(){
this.t3.method1();
}
}
可以使用同一个Test3 实例构造多个多个MyThread4 线程并依次启动,就可以测出锁竞争
本人才疏学浅,一点心得与大家分享,如有错误,欢迎指教,如果觉得不错,也欢迎转载
分享到:
相关推荐
ta_lib-0.5.1-cp312-cp312-win32.whl
课程设计 在线实时的斗兽棋游戏,时间赶,粗暴的使用jQuery + websoket 实现实时H5对战游戏 + java.zip课程设计
ta_lib-0.5.1-cp310-cp310-win_amd64.whl
基于springboot+vue物流系统源码数据库文档.zip
GEE训练教程——Landsat5、8和Sentinel-2、DEM和各2哦想指数下载
知识图谱
333498005787635解决keil下载失败的文件.zip
【微信机器人原理与实现】 微信机器人是通过模拟微信客户端的行为,自动处理消息、发送消息的程序。在Python中实现微信机器人的主要库是WeChatBot,它提供了丰富的接口,允许开发者方便地进行微信消息的接收与发送。这个项目标题中的"基于python实现的微信机器人源码"指的是使用Python编程语言编写的微信机器人程序。 1. **Python基础**:Python是一种高级编程语言,以其简洁的语法和强大的功能深受开发者喜爱。在实现微信机器人时,你需要熟悉Python的基本语法、数据类型、函数、类以及异常处理等概念。 2. **微信API与WeChatBot库**:微信为开发者提供了微信公共平台和微信开放平台,可以获取到必要的API来实现机器人功能。WeChatBot库是Python中一个用于微信开发的第三方库,它封装了微信的API,简化了消息处理的流程。使用WeChatBot,开发者可以快速搭建起一个微信机器人。 3. **微信OAuth2.0授权**:为了能够接入微信,首先需要通过OAuth2.0协议获取用户的授权。用户授权后,机器人可以获取到微信用户的身份信息,从而进行
基于springboot实验室研究生信息管理系统源码数据库文档.zip
张力控制,色标跟踪,多轴同步,电子凸轮,横切等工艺控制案例。
在Python编程环境中,处理Microsoft Word文档是一项常见的任务。Python提供了几个库来实现这一目标,如`python-docx`,它可以让我们创建、修改和操作.docx文件。本教程将重点介绍如何利用Python进行Word文档的合并、格式转换以及转换为PDF。 1. **合并Word文档(merge4docx)** 合并多个Word文档是一项实用的功能,特别是在处理大量报告或文档集合时。在Python中,可以使用`python-docx`库实现。我们需要导入`docx`模块,然后读取每个文档并将其内容插入到主文档中。以下是一个基本示例: ```python from docx import Document def merge4docx(file_list, output_file): main_doc = Document() for file in file_list: doc = Document(file) for paragraph in doc.paragraphs: main_doc.add_paragraph(paragraph.text) m
基于springboot+Javaweb的二手图书交易系统源码数据库文档.zip
基于springboot餐品美食论坛源码数据库文档.zip
基于springboot亚运会志愿者管理系统源码数据库文档.zip
使用WPF的数据样式绑定,切换对象数据值来完成控件动态切换背景渐变动画效果。 使用动画样式渲染比线程修改性能消耗更低更稳定
基于SpringBoot的企业客源关系管理系统源码数据库文档.zip
基于springboot+vue的桂林旅游网站系统源码数据库文档.zip
基于springboot嗨玩旅游网站源码数据库文档.zip
基于springboot的流浪动物管理系统源码数据库文档.zip
基于springboot课件通中小学教学课件共享平台源码数据库文档.zip