同步代码块

synchronized(obj) {//代码块

}

obj 为同步监视器,以上代码的含义为:线程开始执行同步代码块(中的代码)之前,必须先获得对同步监视器的锁定。

代码块中的代码是执行代码,即是某个方法中的某一部分代码,synchronized(obj){}只能出现在某个方法中。如:

public voidtest() {synchronized(obj) {//代码块

}

}

而不能出现在其他位置,如下则报错:

public classTest {publicvoidtest(String[] strs) {}

// 报错,只能出现在某个方法中synchronized(obj) {

}

}

同步代码块示例:

定义一个Account类,用于存储账户金额

classAccount {//账户余额

private doublebalance;public Account(doublebalance) {this.balance =balance;

}//设置余额

public void setBalance(doublebalance) {this.balance =balance;

}//取出余额

public doublegetBalance() {returnbalance;

}

}

定义1个线程类用于对某个账户进行操作(取出账户中的余额),该线程类不包含同步代码块

class DrawMoney extendsThread {private Account account; //待取账户

private double amount; //取出金额

public DrawMoney(Account account, doubleamount) {this.account =account;this.amount =amount;

}//取出account中的余额,取出数量为amount

public voidrun() {//若account中的余额大于等于amount,取钱成功

if (amount <=account.getBalance()) {

System.out.println(getName()+ " : " + "Get money:" +amount);//线程休眠2毫秒

try{

Thread.sleep(2);

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

account.setBalance(account.getBalance()-amount);

System.out.println(getName()+ " : " + "Balance is " +account.getBalance());

}elseSystem.out.println("The balance is not enough");

}

}

使用上述Account类及DrawMoney类定义一个账户,两个用户,两个用户同时对账户操作(取钱)。

public classSynchronizedTest {public static voidmain(String[] args) {

Account account= new Account(100);

DrawMoney user1= new DrawMoney(account, 70);

DrawMoney user2= new DrawMoney(account, 70);

user1.start();

user2.start();

}

}

运行结果:

Thread-0 : Get money:70.0

Thread-1 : Get money:70.0

Thread-0 : Balance is 30.0

Thread-1 : Balance is -40.0

由上可知,第二个用户取钱出现错误,余额不应当小于0。这是由于两个并发运行的线程(同时取钱的用户)同时对account操作,而不是一个取钱完成,再交给下一个。用户1还没来得及修改余额,用户2就开始取钱。

修改上述线程类,同步其中的取钱操作

class DrawCash extendsThread {privateAccount account;private doubleamount;public DrawCash(Account account, doubleamount) {this.account =account;this.amount =amount;

}public voidrun() {//使用account作为同步监视器,线程在执行下面的代码之前需要先锁定account

synchronized(account) {if (amount <=account.getBalance()) {

System.out.println(getName()+ " : " + "Get money:" +amount);try{

Thread.sleep(2);

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

account.setBalance(account.getBalance()-amount);

System.out.println(getName()+ " : " + "Balance is " +account.getBalance());

}elseSystem.out.println(getName()+ " : " + "The balance is not enough");

}

}

}

这时

public classSynchronizedTest {public static voidmain(String[] args) {

Account account= new Account(100);

DrawCash user1= new DrawCash(account, 70);

DrawCash user2= new DrawCash(account, 70);

user1.start();

user2.start();

}

}

运行结果:

Thread-0 : Get money:70.0

Thread-0 : Balance is 30.0

Thread-1 : The balance is not enough

第一个线程执行同步代码块时锁定监视器account,第二个线程执行同步代码块时也需要锁定监视器account,

但此时account被线程0锁定,故线程1只有在线程0的同步代码块执行完毕后才能执行其同步代码块。

使用DrawMoney与DrawCash各定义一个用户,对同一个账户取钱。

public classSynchronizedTest {public static voidmain(String[] args) {

Account account= new Account(100);

DrawCash user1= new DrawCash(account, 70);

DrawMoney user2= new DrawMoney(account, 70);

user1.start();

user2.start();

}

}

运行结果:

Thread-0 : Get money:70.0

Thread-1 : Get money:70.0

Thread-0 : Balance is 30.0

Thread-1 : Balance is -40.0

结果依旧出错,这是由于线程0需要锁定监视器account,但线程1不需要,故该情况下account的访问仍会出现线程不安全。

同步方法

被synchronized修饰的方法为同步方法,同步方法的同步监视器为this,即与该方法对应的对象(该方法所在的类生成的对象)。

public synchronized void draw() {}

某个线程若要调用draw()方法,需要先锁定draw()对应的对象。

修改Account类,添加同步方法

classAccount {//账户余额

private doublebalance;public Account(doublebalance) {this.balance =balance;

}public synchronized void draw(doubleamount) {if (amount >balance)

System.out.println(Thread.currentThread().getName()+ " : " + "Balance is not enough");else{

System.out.println(Thread.currentThread().getName()+ " : " +amount);

balance-=amount;

System.out.println(Thread.currentThread().getName()+ " : " + "Balance is " +balance);

}

}

}

修改DrawMoney类

class DrawMoney extendsThread {private Account account; //待取账户

private double amount; //取出金额

public DrawMoney(Account account, doubleamount) {this.account =account;this.amount =amount;

}//取出account中的余额,取出数量为amount

public voidrun() {account.draw(amount);

}

}

这时

public classSynchronizedTest {public static voidmain(String[] args) {

Account account= new Account(100);

DrawMoney user1= new DrawMoney(account, 70);

DrawMoney user2= new DrawMoney(account, 70);

user1.start();

user2.start();

}

}

运行结果:

Thread-0 : 70.0

Thread-0 : Balance is 30.0

Thread-1 : Balance is not enough

可见,线程是安全的

线程0调用draw()方法时锁定监视器account,1线程调用draw()时也需要锁定监视器account,

但此时account被线程0锁定,故线程1只有在线程0的调用完毕后才能调用。

上述的同步方法也可以用同步代码块实现:

classAccount {//账户余额

private doublebalance;public Account(doublebalance) {this.balance =balance;

}

public void draw(doubleamount) {synchronized (this) {if (amount >balance)

System.out.println(Thread.currentThread().getName()+ " : " + "Balance is not enough");else{

System.out.println(Thread.currentThread().getName()+ " : " +amount);

balance-=amount;

System.out.println(Thread.currentThread().getName()+ " : " + "Balance is " +balance);

}

}

}

}

总结:

同步代码块与同步方法都是表明在执行某段代码前需要先锁定某个对象,同步代码块需指定,同步方法默认为this。

java同步方法同步块_java 同步代码块与同步方法相关推荐

  1. java类静态初始化_Java静态代码块和类初始化、实例初始化过程

    1. 静态代码块 静态代码块:定义在类中方法外,使用static修饰 ①可以为类变量(静态变量)初始化 ②静态代码块在第一次使用这个类之前执行,即在类初始化时执行,且只执行一次 ③若有多个静态代码块, ...

  2. java 静态代码块_JAVA静态代码块

    今天遇到下面的代码,感觉很奇怪,特意记录下: 代码如下: public class Test { private static List objs = new ArrayList(); static ...

  3. 牛客网Java刷题知识点之什么是代码块、普通代码块、静态代码块、同步代码块、构造代码块以及执行顺序...

    不多说,直接上干货! 这种形式的程序段我们将其称之为代码块,所谓代码块就是用大括号({})将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法.一般来说代码块是不能单独运行的,它必须要有运行 ...

  4. java 代码块(局部代码块、实例代码块、静态代码块、同步代码块)

    1 引言 代码块是类的成分之一:成员变量,方法,构造器,代码块,内部类. 在Java中,使用 { } 括起来的代码被称为代码块(Code block) 1.1 代码块的分类 根据其位置和声明的不同,可 ...

  5. 代码块(普通代码块、构造代码块、静态代码块、同步代码块)、初始化(类初始化、对象初始化)

    普通代码块:类里的代码块,方法里的代码块,语句代码块,{} 构造代码块:直接写在类里方法外的代码块,用来对实例对象进行初始化 静态代码块:语法上,在构造代码块前加一个static,用来对类进行初始化 ...

  6. java构造块_java中的静态代码块、构造代码块、构造方法详解

    运行下面这段代码,观察其结果: package com.test; public class HelloB extends HelloA { public HelloB() { } { System. ...

  7. java静态代码块和构造方法_Java静态代码块和构造方法执行顺序

    package com.uno.staticBlock; import java.lang.reflect.Field; import java.util.Vector; /** * 验证静态代码块和 ...

  8. java子类代码块_java中父类子类静态代码块、构造代码块执行顺序

    父类静态(代码块,变量赋值二者按顺序执行) 子类静态 父类构造代码块 父类构造方法 子类构造代码块 子类构造方法 普通方法在实列调用的时候执行,肯定位于上面之后了 //父类A public class ...

  9. Java基础篇:四种代码块详解

    所谓代码块,就是用大括号{}将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法.一般来说,代码块是不能单独运行的,它必须有运行主体.在Java中代码块主要分为四种:普通代码块.静态代码块. ...

最新文章

  1. NFS网络文件共享存储服务器
  2. linux中的SGI(核间中断)IPI_RESCHEDULE详解
  3. Python学习—基础数据结构之列表
  4. php5.4.41 绿色_编译安装PHP5.4.41
  5. execution 排除_使用SQL Server 2016 Live Execution统计信息对SQL查询性能进行故障排除
  6. PIL Error, TypeError: Cannot handle this data type:(1, 1), <i8
  7. 算法竞赛入门经典(第二版) 答案汇总(持续更新)
  8. 跟随企业数字化转型,FIT2CLOUD推演全栈云管平台
  9. c++系列:关于MSVCR100.dll、MSVCR100d.dll、Msvcp100.dll、Msvcp100D.dll 故障查及解决方法
  10. java 让坦克移动_坦克大战_坦克移动
  11. 前端cookie设置httpOnly和secure拿不到,换成localstorage+加密方式
  12. 计算机打印机无法共享怎么设置密码,打印机共享设置密码【调解思路】
  13. malloc(): corrupted top size 解决
  14. zbrush是什么软件
  15. python xlsx 转csv
  16. 电商html轮播动效,制作一个电商网站的轮播图效果
  17. 织梦DEDECMS 整合Kindeditor编辑器美化版nkeditor版可H5多图上传摒弃SWF上传
  18. 计算机应用基础第二版在线作业c,计算机应用基础(第2版)-在线作业_C.doc
  19. 变革边缘——Web3.0の野望(上)
  20. 重邮大学计算机基础考试试题及答案,重庆邮电大学《大学计算机基础(2015》考试试卷.pdf...

热门文章

  1. 玩转Hook——Android权限管理功能探讨(一)
  2. 《一个程序员的奋斗史》帮我选封面哇! —— 猜封面页数赢赠书活动~
  3. IOS 归档 即序列化与反序列化
  4. 10个修复ie6下bug技巧[转]
  5. 6个最佳的开源Python应用服务器
  6. pycharm如何修改文件名
  7. Ubuntu18.04安装Gstreamer1.0(六)
  8. 深入剖析Android音频(四)AudioTrack
  9. 如何添加行号 c语言,如何为程序代码加上行号
  10. JAVA提示定义常量_如何在Java中定义常量(Constant)