Java在多线程中使用同步锁机制时,一定要注意锁对对象,下面的例子就是没锁对对象(每个线程使用一个被锁住的对象时,得先看该对象的被锁住部分是否有人在使用)

例子:两个人操作同一个银行账户,丈夫在ATM机上操作,妻子在银行柜台操作

账户类:账户里面有100万

public class Acount {
public int money=100;
}

ATM机类:里面存在一个Acount对象和要取的钱数,在takeMoney方法中加了synchronized 机制

public class ATM implements Runnable{
private Acount acount;
private int withdrawMoney; public ATM(Acount acount, int withdrawMoney) {
this.acount = acount;
this.withdrawMoney = withdrawMoney;
} @Override
public void run() {
takeMoney();
} public synchronized void takeMoney(){ //取钱
if(acount.money<withdrawMoney){
return;
}
try {
Thread.sleep(200); //线程1进入后休眠,线程2仍可以进来,这样可能造成赤字
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"取出"+withdrawMoney+"万元");
acount.money-=withdrawMoney;
System.out.println("账户余额:"+acount.money);
}
}

客户类:创建一个唯一账户,两台ATM机(其中一台模拟柜台),分别给两个人使用

public class Customer {
public static void main(String[] args) {
Acount acount=new Acount();
ATM atm1=new ATM(acount,70); //丈夫在ATM机上操作账户,妻子在柜台操作账户
ATM atm2=new ATM(acount,80);
Thread husband=new Thread(atm1,"丈夫");
Thread wife=new Thread(atm2,"妻子"); husband.start();
wife.start();
}
}

运行结果:

可以看到加了synchronized 后仍然出现线程不安全。

分析:synchronized 机制一般用在被数据操作的对象中,而takeMoney方法是属于ATM机的方法,在此例子中,一共存在一个账户类,两个ATM机类,两个ATM机类去操作账户类,所以应该把账户类锁住。

修正:使用同步块机制锁住acount对象

public void takeMoney(){    //取钱
synchronized (acount){
if(acount.money<withdrawMoney){
return;
}
try {
Thread.sleep(200); //线程1进入后休眠,线程2仍可以进来,这样可能造成赤字
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"取出"+withdrawMoney+"万元");
acount.money-=withdrawMoney;
System.out.println("账户余额:"+acount.money);
} }

例子2 Tickert类是线程类

public class Ticket implements Runnable{

    private int ticker=100;
private boolean flag=true; @Override
public void run() {
while(flag){
robTicket();
}
} /**
* 抢票
*/
public void robTicket(){
if (ticker <= 0) {
flag = false;
return;
}
synchronized (this){ //多重验证机制,在这里检测这个对象的这部分代码是否被使用,如果有线程正在使用该对象的该部分代码,就等待
if (ticker <= 0) {
flag = false;
return;
}
try { //模拟网络延时
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticker--);
} }
}

主类

public class RobTicket {

    public static void main(String[] args) {
Runnable ticket=new Ticket();
//3个线程同时对一个ticket对象进行操作,准确来说是对ticket对象里面的ticket变量操作
Thread feizhu=new Thread(ticket,"飞猪");
Thread zhixing=new Thread(ticket,"智行");
Thread xiecheng=new Thread(ticket,"携程"); zhixing.start();
feizhu.start();
xiecheng.start();
}
}

在这个例子里面运用了多重的验证机制,保证了抢票重复和抢票出现负数的情况,如果不加synchronized 里面的if判断语句,仍然会出现线程不安全,因为其他线程可能并发的排队在同步块外面等候了,此时如果还剩一张票的话,当前线程抢完这最后一张票后其他线程仍然有机会抢票,这是不合理的,当然可以为整个方法上锁,但是性能会下降。

Java多线程学习——synchronized锁机制的更多相关文章

  1. java 多线程8 : synchronized锁机制 之 方法锁

    脏读 一个常见的概念.在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数 ...

  2. java 多线程9 : synchronized锁机制 之 代码块锁

    synchronized同步代码块 用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间.这种情况下可以尝试使用 ...

  3. java 多线程并发 synchronized 同步机制及方式

    2. 锁机制 3. 并发 Excutor框架 4. 并发性与多线程介绍 1. synchronized  参考1. synchronized 分两种方式进行线程的同步:同步块.同步方法 1. 方法同步 ...

  4. Java多线程,对锁机制的进一步分析

    1 可重入锁 可重入锁,也叫递归锁.它有两层含义,第一,当一个线程在外层函数得到可重入锁后,能直接递归地调用该函数,第二,同一线程在外层函数获得可重入锁后,内层函数可以直接获取该锁对应其它代码的控制权 ...

  5. Java多线程5:Synchronized锁机制

    一.前言 在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的. 二.引入Synchronized ...

  6. Java多线程学习(六)Lock锁的使用

    系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...

  7. Java多线程学习(四)等待/通知(wait/notify)机制

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79690279 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

  8. Java多线程学习(二)synchronized关键字(1)

    转载请备注地址: https://blog.csdn.net/qq_34337272/article/details/79655194 Java多线程学习(二)将分为两篇文章介绍synchronize ...

  9. Java多线程学习(二)synchronized关键字(2)

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79670775 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

随机推荐

  1. react-native启动时红屏报错:Unable to load script.Make sure you're either running a metro server or that ....

    一.报错信息内容 我是在Android Studio中运行启动react-native项目时报的这个错误 1.报错提示:Unable to load script.Make sure you're e ...

  2. 关于FTP和SFTP的操作总结

    SFTP使用的三方类库是Renci.SshNet.DLL SFTP连接大部分网上使用IP地址形式的路径,而我本次使用的是网站形式的.类似sftp.XXX.com SFTP的操作也类似File文件的操作 ...

  3. Java基本的程序结构设计 控制流程

    控制流程 java的控制流程和C和C++基本一致,只是不能使用goto语句,不过break语句可以带标签,实现从内层循环跳出的目的.标签可以放在for或者while前面.如下: package com ...

  4. ArrayList为什么是线程不安全的

    首先需要了解什么是线程安全:线程安全就是说多线程访问同一代码(对象.变量等),不会产生不确定的结果. 既然说ArrayList是线程不安全的,那么在多线程中操作一个ArrayList对象,则会出现不确 ...

  5. Git之协同开发

    Github之协同开发 一.协同开发 1.引子:假如三个人共同开发同一份代码,每个人都各自安排了任务,当每个人都完成了一半的时候,提交不提交呢? 要提交,提交到dev吗,都上传了一半,这样回家拿出来的 ...

  6. hashmap分解大法--tableSizeFor方法

    tableSizeFor方法 /** * 根据容量参数,返回一个2的n次幂的table长度. */ private static final int tableSizeFor(int c) { int ...

  7. python-pillow图像处理

    安装 pip3 install pillow PIL中所涉及的基本概念有如下几个:通道(bands).模式(mode).尺寸(size).坐标系统(coordinate system).调色板(pal ...

  8. NOIP2016提高A组模拟中秋节9.15总结

    这套题不算难但是比赛上萎掉了. 第一题数论, 当找到一个合适的数就直接处理答案,再用筛法将处理过的删掉. 比赛上没想到筛法,只拿了70分. 第二题二分答案,然后验证合法性就可以. 但是由于不能二分小数 ...

  9. 2016.09.03【初中部 NOIP提高组 】模拟赛A总结

    今天班主任不知道出了什么事,把整个班留了40多分钟,各种吹水谈人生.耽误了很多时间. #$%^& 这次第一题很神奇,通过枚举矩阵来确定三个单元格的位置,没想到,结果爆零. 刚开始看见这道题有费 ...

  10. springboot结合jsp页面详解

    第一次写博客,其实就是为了约束我自己,写的不一定对,互相借鉴吧!有不对的地方请多多指正,谢谢! 今天我们来看一下springboot结合jsp页面的具体操作: 1.首先我们先看一下目录结构 由上面我们 ...