同步代码块

synchronized (obj) {
// 代码块
}

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

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

    public void test() {

        synchronized (obj) {
// 代码块
}
}

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

public class Test {

    public void test(String[] strs) {

    }

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

同步代码块示例:

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

class Account {

    // 账户余额
private double balance; public Account(double balance) {
this.balance = balance;
} // 设置余额
public void setBalance(double balance) {
this.balance = balance;
} // 取出余额
public double getBalance() {
return balance;
}
}

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

class DrawMoney extends Thread {

    private Account account;  // 待取账户
private double amount; // 取出金额 public DrawMoney(Account account, double amount) {
this.account = account;
this.amount = amount;
} // 取出account中的余额,取出数量为amount
public void run() {
// 若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());
}
else
System.out.println("The balance is not enough");
}
}

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

public class SynchronizedTest {

    public static void main(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 extends Thread {

    private Account account;
private double amount; public DrawCash(Account account, double amount) {
this.account = account;
this.amount = amount;
} public void run() { // 使用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());
}
else
System.out.println(getName() + " : " + "The balance is not enough");
}
}
}

这时

public class SynchronizedTest {

    public static void main(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 class SynchronizedTest {

    public static void main(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类,添加同步方法

class Account {

    // 账户余额
private double balance; public Account(double balance) {
this.balance = balance;
}
public synchronized void draw(double amount) {
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 extends Thread {

    private Account account;  // 待取账户
private double amount; // 取出金额 public DrawMoney(Account account, double amount) {
this.account = account;
this.amount = amount;
} // 取出account中的余额,取出数量为amount
public void run() {
account.draw(amount);
}
}

这时

public class SynchronizedTest {

    public static void main(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的调用完毕后才能调用。

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

class Account {

    // 账户余额
private double balance; public Account(double balance) {
this.balance = balance;
} public void draw(double amount) { 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 同步代码块与同步方法的更多相关文章

  1. java中的synchronized同步代码块和同步方法的区别

    下面这两段代码有什么区别? //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized ...

  2. Android(java)学习笔记68:同步代码块 和 同步方法 的应用

    1. 同步代码块 和 同步方法 代码示例: (1)目标类,如下: package cn.himi.text; public class SellTicket implements Runnable { ...

  3. Java的synchronized的同步代码块和同步方法的区别

    synchronized同步方法和同步代码块的区别 同步方法默认使用this或者当前类做为锁. 同步代码块可以选择以什么来加锁,比同步方法更精确,我们可以选择只有会在同步发生同步问题的代码加锁,而并不 ...

  4. Android(java)学习笔记8:同步代码块 和 同步方法 的应用

    1. 同步代码块 和 同步方法 代码示例: (1)目标类,如下: package cn.himi.text; public class SellTicket implements Runnable { ...

  5. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  6. java线程基础巩固---同步代码块以及同步方法之间的区别和关系

    在上一次中[http://www.cnblogs.com/webor2006/p/8040369.html]采用同步代码块的方式来实现对线程的同步,如下: 对于同步方法我想都知道,就是将同步关键字声明 ...

  7. 写2个线程,一个打印1-52,一个打印A-Z,打印顺序是12A34B。。。(采用同步代码块和同步方法两种同步方法)

    1.同步方法 package Synchronized; /************************************同步方法****************************** ...

  8. Java 同步代码块 - Synchronized Blocks

    java锁实现原理: http://blog.csdn.net/endlu/article/details/51249156 The synchronized keyword can be used ...

  9. Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...

随机推荐

  1. L256 翻译

    Should work be placed among the causes of happiness or be regarded as a burden? Much work isexceedin ...

  2. 框架:MVC

    MVC 一.介绍 MVC是模型-视图-控制器的缩写,一种软件思想,强制性的把应用程序的输入.处理和输出分开.可以和任何的重定向能解耦. 三部分的任务说明: 视图:获取数据,显示数据 模型:处理数据 控 ...

  3. 解析JSON 注意解析数据为一个对象的情况.--加一下说明

    应用场景: 调某接口时, 获取json数据, 需要对数据进行解析 . 第一种: 只判断接口是否调用成功 { "code":"10102000", "d ...

  4. 训练 の Bessie的体重问题

    Bessie的体重问题 题目描述 Bessie像她的诸多姊妹一样,因为从Farmer John的草地吃了太多美味的草而长出了太多的赘肉.所以FJ将她置于一个及其严格的节食计划之中.她每天不能吃多过H ...

  5. Server SSL certificate verification failed: certificate has expired, issuer is not trusted

    Unable to connect to a repository at URL 'https://xxxxx/svn/include' Server SSL certificate verifica ...

  6. 微软Power BI 每月功能更新系列——5月Power BI 新功能学习

    Power BI Desktop 5月份功能摘要 本月Power BI Desktop除了许多报表功能的更新,Power BI对条件格式进行了重大改进,可以对报表的任何字段(包括字符串和日期)进行条件 ...

  7. 20165228 2017-2018-2《Java程序设计》课程总结

    20165228 2017-2018-2<Java程序设计>课程总结 每周作业链接汇总 预备作业1:我期望的师生关系 简要内容: 老师能给我在学习中提供什么帮助 我的看法 我期望的师生关系 ...

  8. 20155219&20155224 《信息安全系统设计基础》实验二 固件程序设计

    实验二 固件程序设计-1-MDK 0. 注意不经老师允许不准烧写自己修改的代码 1. 两人(个别三人)一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1. ...

  9. HPU组队赛B:问题(二进制枚举)

    时间限制1 Second 内存限制 512 Mb 题目描述 你有n个问题,你已经估计了第i个问题的难度为Ci,现在你想使用这些问题去构造一个问题集.比赛的问题集必须包含至少两个问题,而且比赛的总难度必 ...

  10. 03 事务,连接池DBCP,C3P0,DBUtils

    事务 Transaction  其实指的一组操作,里面包含许多个单一的逻辑.只要有一个逻辑没有执行成功,那么都算失败. 所有的数据都回归到最初的状态(回滚) 事务的作用:为了确保逻辑的成功. 例子: ...