synchronized同步块实例

news/2024/5/17 19:19:02 标签: java, java多线程, thread, synchronized

synchronized同步块实例

       java中,每个对象都包含了一把锁(也叫做“监视器”),它自动成为对象的一部分(不必为此写任何特殊的代码)。在给定时刻,只有一个线程可以拥有一个对象的监视器。

       示例:线程1进入withdrawal方法时,获得监视器(加锁);当线程1的方法执行完毕返回时,释放监视器(开锁),线程2withdrawal方能进入

      

 

synchronized

a.       为了确保在任何时刻一个共享对象只被一个线程使用,必须使用“同步(synchronized)

b.       有两种方式实现同步

a)         使用同步方法

synchronized void methodA() {}

b)        使用同步块

synchronized(obj) {       //obj是被锁定的对象

       //要同步的语句

}

c.       synchronized来标识的块或方法即为监视器监视的部分。只有使用synchronized,才能利用对象的监视器功能

d.       调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized方法,除非第一个方法完成了自已的工作,并解除锁定。因此,一个特定对象的所有synchronized方法都共享着一把锁,而且这把锁能防止多个方法对通用内存同时进行写操作(比如同时有多个线程)【任何一个Object有且仅有一把锁,所以方法级的synchronized会对其它有synchronized的方法也起作用,即运行时,此对象最多只能有一个带有synchronized的方法运行】

e.       每个类也有自已的一把锁(作为类的Class对象的一部分),所以synchronized static方法可在一个类的范围内被相互间锁定起来,防止与static数据的接触

f.        一般情况下,只在方法的层次上使用同步

 

实例:

 

java">package com.bijian.thread;

/*
 * 定义了操作类型和金额
 */
public class FinTrans {

	public static String transName;
	public static double amount;
}

 

java">package com.bijian.thread;

public class TransThread extends Thread {

	private FinTrans ft;

	TransThread(FinTrans ft, String name) {
		super(name); // Save thread's name
		this.ft = ft; // Save reference to financial transaction object
	}

	public void run() {
		for (int i = 0; i < 100; i++) {
			if (getName().equals("Deposit Thread")) {
				// Start of deposit thread's critical code section
				// 存款操作(每次存2000元)
				ft.transName = "Deposit";
				try {
					Thread.sleep((int) (Math.random() * 1000));
				} catch (InterruptedException e) {
				}
				ft.amount = 2000.0;
				System.out.println(ft.transName + " " + ft.amount);
				// End of deposit thread's critical code section
			} else {
				// Start of withdrawal thread's critical code section
				// 取款操作(每次取250元)
				ft.transName = "Withdrawal";
				try {
					Thread.sleep((int) (Math.random() * 1000));
				} catch (InterruptedException e) {
				}
				ft.amount = 250.0;
				System.out.println(ft.transName + " " + ft.amount);
				// End of withdrawal thread's critical code section
			}
		}
	}
}

 

java">package com.bijian.thread;

public class NeedForSynchronizationDemo {
	public static void main(String[] args) {
		
		FinTrans ft = new FinTrans();
		TransThread tt1 = new TransThread(ft, "Deposit Thread");
		TransThread tt2 = new TransThread(ft, "Withdrawal Thread");
		tt1.start();
		tt2.start();
	}
}

 运行结果:

Withdrawal 250.0
Withdrawal 2000.0
Deposit 250.0
Withdrawal 2000.0
Deposit 250.0
Withdrawal 2000.0
Deposit 250.0
Withdrawal 2000.0
Deposit 250.0
Withdrawal 2000.0
Deposit 250.0
…

 

发现 Withdrawal 的操作金额有些变成了 2000.0 ,而 Deposit 的操作金额有些变成了 250.0

 

一.同步块解决

修改TransThread类,加上synchronized同步块,如下所示:

java">package com.bijian.thread;

public class TransThread extends Thread {

	private FinTrans ft;

	TransThread(FinTrans ft, String name) {
		super(name); // Save thread's name
		this.ft = ft; // Save reference to financial transaction object
	}

	public void run() {
		
		for (int i = 0; i < 100; i++) {
			if (getName().equals("Deposit Thread")) {
				synchronized (ft) {
					ft.transName = "Deposit";
					try {
						Thread.sleep((int) (Math.random() * 1000));
					} catch (InterruptedException e) {
					}
					ft.amount = 2000.0;
					System.out.println(ft.transName + " " + ft.amount);
				}
			} else {
				synchronized (ft) {
					ft.transName = "Withdrawal";
					try {
						Thread.sleep((int) (Math.random() * 1000));
					} catch (InterruptedException e) {
					}
					ft.amount = 250.0;
					System.out.println(ft.transName + " " + ft.amount);
				}
			}
		}
	}
}

 

运行结果如下所示:
Deposit 2000.0
Deposit 2000.0
Withdrawal 250.0
Withdrawal 250.0
Deposit 2000.0
Deposit 2000.0
Deposit 2000.0
Withdrawal 250.0
Withdrawal 250.0
Deposit 2000.0

 

 

二.同步方法解决

       按现实中的场景,同步的动作应该放在FinTrans类中,而不应由访问的第三方来控制,因此修改实例如下。

 

java">package com.bijian.thread;

public class FinTrans {

	private String transName;
	private double amount;

	public synchronized void update(String transName, double amount) {
		this.transName = transName;
		this.amount = amount;
		System.out.println(this.transName + " " + this.amount);
	}
	
	public synchronized void save(double amount) {
		this.transName = "Withdrawal";
		this.amount = amount;
		System.out.println(this.transName + " " + this.amount);
		try {
			Thread.sleep((int) (Math.random() * 1000));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public synchronized void take(double amount) {
		this.transName = "Deposit";
		this.amount = amount;
		System.out.println(this.transName + " " + this.amount);
		try {
			Thread.sleep((int) (Math.random() * 1000));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

java">package com.bijian.thread;

public class TransThread extends Thread {

	private FinTrans ft;

	TransThread(FinTrans ft, String name) {
		super(name); // Save thread's name
		this.ft = ft; // Save reference to financial transaction object
	}

	public void run() {
		for (int i = 0; i < 100; i++)
			if (getName().equals("Deposit Thread"))
				ft.take(2000.0);
			else
				ft.save(250.0);
	}
}

  

运行 NeedForSynchronizationDemo 类的 main 方法,结果如下所示:
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
Deposit 2000.0
Withdrawal 250.0
Deposit 2000.0
…

 


http://www.niftyadmin.cn/n/1319110.html

相关文章

大数据可视化管理antV使用详解

首先给大家看看官网的图表是不是眼花缭乱&#xff0c;不要怕接下来我将会给小白同学一步步解开antv的神秘面纱 目录 安装antV第一个antV组件关于自定义antV图标的一些样式关于常用的api介绍五字真言 1.首先在项目中引入antv npm install antv/g2 --save2.开始书写你的图标组件…

SQL2000自动备份 删除

好久没用SQL2000&#xff0c;今天要为旧项目写个备份和删除数据的功能&#xff0c;代码如下 declare dbname varchar(20),cmd1 nvarchar(120),cmd2 varchar(120),cmd3 varchar(120),i int,filename varchar(80),path varchar(80)set dbnameTEST--\\这是数据库名&#xff0c;使用…

wait-notify机制

wait-notify机制 a. 当synchronized方法中的wait方法被调用时&#xff0c;当前线程将被中断运行&#xff0c;并且放弃该对象的锁 b. 一旦线程调用了wait方法&#xff0c;它便进入该对象的等待列表。要从等待列表中删除该线程&#xff0c;使它有机会继续运行&#x…

常见的时间格式转换工具函数

写在前面的话 当你还在为日期格式之间的相互转换抓耳挠腮时&#xff0c;那么你的福音来了本本片博客主要提供了五中通过原生的JavaScript实现常见的日期格式之间的各种转换,希望能帮助你解决问题 当你被迫从梦中醒来打开电脑&#xff0c;发现原来是在传参的时候日期格式不对&…

电商课题VII:支付交易一般性准则

郑昀汇总 创建于2012/11 发布版本号&#xff1a;v1.3概念&#xff1a;退款期限&#xff0c;交易&#xff0c;交易关闭&#xff0c;交易结束&#xff0c;掉单&#xff0c;幂等性&#xff0c;数据一致性关键词&#xff1a;历史记录不得直接篡改原则&#xff0c;交易关闭通知处理&…

简单生产消费者问题

生产者-消费者问题 a. 在多线程程序中&#xff0c;可能出现生产者-消费者问题&#xff0c;即等待同步数据的问题 b. 可能出现的问题&#xff1a; a) 生产者比消费者快时&#xff0c;消费者会漏掉一些数据没有取到 b) 消费者比生产者快时&#xff0…

Vue中Axios使用详解

目录 Axios介绍Axios安装Axios二次封装 1. Axios介绍 什么是 axios&#xff1f; Axios 是一个基于 promise 的 HTTP 库&#xff0c;可以用在浏览器和 node.js 中。 特性 从浏览器中创建 XMLHttpRequests&#xff08;和原生的Ajax相同都是基于XMLHttpRequest&#xff08;&…

移动平台3G手机网站前端开发布局技巧汇总(转)

自Iphone和Android这两个牛逼的手机操作系统发布以来&#xff0c;在互联网界从此就多了一个新的名词-WebApp(意为基于WEB形式的应用程序&#xff0c;运行在高端的移动终端设备)。 开发者们都知道在高端智能手机系统中有两种应用程序&#xff1a;一种是基于本地&#xff08;操作…