如果有多个线程访问共享资源,可能会出现当一个线程没有处理完业务,然后另一个线程进入,从而导致共享资源出现不安全的情况。

日常例子:银行取钱,A和B有拥有同一个银行账户,A用存折在柜台取钱,B在取款机取钱。取钱有两个关键步骤:
(1)判断账户里的钱的余额是否大于所取钱数
(2)如果大于所取钱数,则账户最终所剩余额 = 余额 - 所取钱数。
如果没有线程同步的情况下,我们假设这一种情况,这个共同的账户里共1000元。
(1)A B同时去取600元,A所在线程执行到上面的第一个步骤,判断所取钱数小于现有余额,CPU时间片用完。
(2)这时B进来到第一个步骤,同样是执行判断,因为A只执行完第一步骤,没有执行减法,这时现有余额还是1000元。
(3)由于在CPU分配的时间里他接着完成了减法操作。这时账户余额为1000 - 600 = 400。成功取出600元。
(4)最后A接着之前执行的步骤,去做减法操作, 账户余额为 -200 = 400 - 600。
到这里,我只想说为什么,是什么银行可以允许你这么做, 当然,除非银行是你家开的。
总之银行不可能让这种情况发生,所以我们的伟大先贤们就想到线程同步,其实很简单,你也能想到。如果让这两个步骤同时完成,不可分开,问题也就迎刃而解。
下面就说到在JAVA中同步代码的实现:
涉及概念:同步监视器,是一个普通的java对象,同一个同步监视器如果一个线程拿到,则其他线程就没有办法拿到。好像是一个房门里只有唯一的一把钥匙, 不能复制。如果一个人拿着它进入房门,其他人只能在外面等候。等他出来你获得了它,你才能进入房间。
下面的代码如果没有做线程同步操作(同步代码块、同步方法、同步锁)结果是如下:
Thread-1------判断所取钱数是否大于余额------
Thread-0------判断所取钱数是否大于余额------
Thread-0======做减法操作,取出现金======
Thread-1======做减法操作,取出现金======
很显然线程1的那两步没有同时完成。
下面的几种方法可以实现两步同时完成。
1、同步代码块:
public class ThreadTest {
public static void main(String[] args){
Thread t1 = new Thread1(); //线程1
Thread t2 = new Thread1();//线程2
t1.start();
t2.start();
}
}
class Thread1 extends Thread{
@Override
public void run() {
super.run();
try {
BeTested b = new BeTested(); // 这地方,因为这个例子中同步监视器 obj 是线程共享的,两个线程用两个不同的对象,也没有关系,不影响结果。
b.beTested(this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BeTested {
static Object obj = new Object();;
public void beTested(Thread t) throws InterruptedException{
synchronized (obj) { // obj 为同步监视器
System.out.println(t.getName() + "------判断所取钱数是否大于余额------");
t.sleep(1000); // 如果没有同步这样能理明显地看到这两步骤不能在一个线程,同一个时间片里执行完成。
System.out.println(t.getName() + "======做减法操作,取出现金======");
}
}
}
执行结果如下:
Thread-0------判断所取钱数是否大于余额------
Thread-0======做减法操作,取出现金======
Thread-1------判断所取钱数是否大于余额------
Thread-1======做减法操作,取出现金======
注意:同步监视器对象的选用很关键。要选择线程共享的对象,比如上面例子的 obj, 它是static修饰的才行,如果没有static修饰,则是使用不同的同步监视器(不是同一个对象),相当于是两把钥匙。
(如果obj = "aaaa" 没有static修饰也可以实现同步,那是因为这个obj引用的常量池里的同一个string对象,强烈不推荐使用)
2、同步方法(非静态方法)
把上面的那两类改成如下,main方法所在类不变。
class Thread1 extends Thread{
static BeTested b = new BeTested(); // 在这种方法中,这里必须是同个对象(static修饰),下文会详细说明
@Override
public void run() {
super.run();
try {
b.beTested(this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BeTested {
static Object obj = new Object();;
public synchronized void beTested(Thread t) throws InterruptedException{
System.out.println(t.getName() + "------判断所取钱数是否大于余额------");
t.sleep(1000);
System.out.println(t.getName() + "======做减法操作,取出现金======");
}
}
执行结果如下:
Thread-0------判断所取钱数是否大于余额------
Thread-0======做减法操作,取出现金======
Thread-1------判断所取钱数是否大于余额------
Thread-1======做减法操作,取出现金======
注意:因为同步方法中,所用的同步监视器不能指定,默认使用的调用该方法的对象,也就是this。所以 Thread1 类中相对于示例1中同步代码块中修改的部分, 也是要static修饰。也就是说要使用同一个对象。
3、同步方法(静态方法)
把上面的那两类改成如下,main方法所在类不变。
class Thread1 extends Thread{
@Override
public void run() {
super.run();
try {
BeTested b = new BeTested(); // 这里每个线程使用不同的对象。
b.beTested(this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BeTested {
static Object obj = new Object();;
public static synchronized void beTested(Thread t) throws InterruptedException{
System.out.println(t.getName() + "------判断所取钱数是否大于余额------");
t.sleep(1000);
System.out.println(t.getName() + "======做减法操作,取出现金======");
}
}
执行结果如下:
Thread-0------判断所取钱数是否大于余额------
Thread-0======做减法操作,取出现金======
Thread-1------判断所取钱数是否大于余额------
Thread-1======做减法操作,取出现金======
注意:因为同步静态方法中,同步监视器是这个类而不是这个类的对象。所以Thread1 类中相对于示例2中同步代码块中修改的部分,不须要用static修饰,不是同一个对象也没关系。因为这个类他本身就是共享的。
总结:如上几种方式进行线程同步处理时,要注意你所使用的同步监视器对象,它必须是共享的。
注:还有使用同步锁的方式实现线程同步,本篇文章不做讨论。
以上这篇浅谈同步监视器之同步代码块、同步方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
# 同步监视器
# java 中同步方法和同步代码块的区别详解
# java多线程-同步块实例讲解
# java中synchronized(同步代码块和同步方法)详解及区别
# 取钱
# 如果没有
# 是一个
# 也没
# 给大家
# 可以实现
# 相对于
# 两步
# 两类
# 类中
# 余额为
# 这一
# 第一个
# 也就
# 多个
# 在这
# 我只
# 则是
# 也能
# 推荐使用
相关文章:
香港服务器网站推广:SEO优化与外贸独立站搭建策略
建站主机是否属于云主机类型?
较简单的网站制作软件有哪些,手机版网页制作用什么软件?
单页制作网站有哪些,朋友给我发了一个单页网站,我应该怎么修改才能把他变成自己的呢,请求高手指点迷津?
佛山企业网站制作公司有哪些,沟通100网上服务官网?
建站之星如何取消后台验证码生成?
建站之星如何实现五合一智能建站与营销推广?
七夕网站制作视频,七夕大促活动怎么报名?
PHP 500报错的快速解决方法
如何获取免费开源的自助建站系统源码?
如何打造高效商业网站?建站目的决定转化率
MySQL查询结果复制到新表的方法(更新、插入)
如何快速使用云服务器搭建个人网站?
巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成
定制建站方案优化指南:企业官网开发与建站费用解析
微网站制作教程,我微信里的网站怎么才能复制到浏览器里?
广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?
宁波自助建站系统如何快速打造专业企业网站?
如何快速搭建个人网站并优化SEO?
建站之星与建站宝盒如何选择最佳方案?
如何通过虚拟主机快速搭建个人网站?
寿县云建站:智能SEO优化与多行业模板快速上线指南
如何使用Golang table-driven基准测试_多组数据测量函数效率
如何在万网ECS上快速搭建专属网站?
红河网站制作公司,红河事业单位身份证如何上传?
如何配置支付宝与微信支付功能?
焦点电影公司作品,电影焦点结局是什么?
如何在Ubuntu系统下快速搭建WordPress个人网站?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
沈阳制作网站公司排名,沈阳装饰协会官方网站?
如何配置IIS站点权限与局域网访问?
贸易公司网站制作流程,出口贸易网站设计怎么做?
小建面朝正北,A点实际方位是否存在偏差?
如何在万网自助建站平台快速创建网站?
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
XML的“混合内容”是什么 怎么用DTD或XSD定义
网站视频怎么制作,哪个网站可以免费收看好莱坞经典大片?
*服务器网站为何频现安全漏洞?
建站之星2.7模板:企业网站建设与h5定制设计专题
网站企业制作流程,用什么语言做企业网站比较好?
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?
潮流网站制作头像软件下载,适合母子的网名有哪些?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
活动邀请函制作网站有哪些,活动邀请函文案?
公司网站制作价格怎么算,公司办个官网需要多少钱?
如何在景安云服务器上绑定域名并配置虚拟主机?
代购小票制作网站有哪些,购物小票的简要说明?
如何在腾讯云服务器上快速搭建个人网站?
C++如何使用std::optional?(处理可选值)
*请认真填写需求信息,我们会在24小时内与您取得联系。