java源码展示:
银行:Account.java
package testsynchrozied;
/**
* 账户类
* @author superdrew
*
*/
public class Account {
private int balance = 600;//余额
//显示余额
public int getBalance(){
return balance;
}
//取款
public void draw(int money){
balance = balance - money;
}
}
银行线程:AccountRunnable.java
package testsynchrozied;
public class AccountRunnable implements Runnable{
Account account = new Account();//取款的账户
Object obj = new Object();
public void run() {
synchronized(obj){ //synchronized 同步 加锁 默认是 open状态 --close()--open
//省略 300行代码
if(account.getBalance()>=400){//余额大于400就取钱
try {
Thread.sleep(1);//第一个线程 进入阻塞,取钱了 线程死亡了
//第二个线程 进入阻塞 取钱了 线程死亡了
} catch (InterruptedException e) {
e.printStackTrace();
}
account.draw(400);
System.out.println("取款成功,当前余额:"+account.getBalance()+"当前线程为:"+Thread.currentThread().getName());
}else{
System.out.println("余额不足,当前余额:"+account.getBalance()+"当前线程为:"+Thread.currentThread().getName());
}
//省略 500行代码
}
//解锁 释放锁
}
public void method1(){
synchronized(obj){
}
}
public void method2(){
synchronized(account){
}
}
public void method3(){
synchronized(account){
}
}
}
测试银行取款主线程:TestSynchronized.java
package testsynchrozied;
/**
* 功能:多个用户同时对一个账户取款
* 使用线程的同步
*
* 1.设计一个账户类 余额,取款,显示余额
* 2.取款的线程
* 3.用户同时取款
*
* 解决方案1:同步代码块 synchronized(account){ .... }
*
* 总结:1.认识同步监视器 account
* synchronized(同步监视器){ ... }
* 1.必须是引用类型的数据,不能是基本数据类型
* 2.在同步代码块中,不要改变引用类型数据的值,属性的值可以修改
* 3.尽量不要使用String 和 包装类做同步监视器,除非代码块中不会改变其内容
* 4.一般是使用共享资源作为同步监视器 (account)
* 5.可以新建一个专门的同步监视器 Object 没有具体的业务含义
*
* 2.之前见过的同步监视器
* StringBuffer Hashtabale vector
*
* 3.同步代码块的执行过程
* 1.第一个线程来到同步代码块,发现同步监视器是open状态,需要close,进去执行里面的代码
* 2.执行里面的代码发生了一些情况 ,切换(阻塞,就绪),第一个线程失去cpu,锁 还是close
* 3.第二个线程来到同步代码块,发现同步监视器是close状态,无法执行,其中的代码也不能执行,
* 第二个线程进入阻塞状态
* 4.第一个线程再次获取cpu,接着执行后续代码,执行完毕,锁 open 第一个线程进入死亡状态
* 5.第二个线程再次获取cpu,又同步代码块,发现锁是open状态,执行后续代码.重复第一个线程的过程
*
* 4.线程同步的有点和缺点
* 优点:安全
* 缺点:效率低下,有可能出现死锁
*
* 5.多个同步代码块使用的是同一个同步监视器(锁),锁住其中一个代码块同时也会锁住其它的所有使用该同步监视器(锁)代码块
* 其它线程无法访问其中任何一个代码块
* 但是没有锁住其它的同步监视器代码块
*/
public class TestSynchronized {
public static void main(String[] args) {
AccountRunnable ar = new AccountRunnable();
Thread th1 = new Thread(ar);
th1.setName("Drew");
Thread th2 = new Thread(ar);
th2.setName("Super");
th1.start();
th2.start();
}
}
结果展示:
![](https://images2017.cnblogs.com/blog/1301422/201712/1301422-20171223113654615-863274437.png)