JSPCN主页
JSP空间
VPS主机
JSP论坛
JSP技术
JSP下载
关于我们
联系我们
当前位置:
首页
-->
JSP文章
-->
JAVA技术
-->
JAVA线程
--> Java多线程同步教程--BusyFlag或Lock (下)
Java多线程程序设计
开发线程安全的Spring Web应用[2005.1]
对Swing线程的再思索 (上)
对Swing线程的再思索 (下)
使用Swing Worker线程 --执行后台任务的新方法
Swing线程的最后讨论 -- 利用异步模型
使用多线程延缓JTextField中数值改变事件激发时间
关于多线程同步的初步教程--使用synchronized
Java多线程同步教程--BusyFlag或Lock (上)
Java多线程同步教程--BusyFlag或Lock (下)
关于多线程同步的初步教程--Metux的设计及使用
如何使用线程
编写高效的线程安全类
Java 线程/内存模型的缺陷和增强
关于多线程同步的初步教程--Simaphore的设计及使用
关于多线程同步的初步教程--Barrier的设计及使用
Java之多线程(2)
JAVA 的多线程浅析
关于Eclipse中UI程序的线程的讨论
Java线程总结
更多...
Java多线程同步教程--BusyFlag或Lock (下)
作者: 文章来源:
发布日期:2007年04月13日
请首先阅读上篇:
Java多线程同步教程--BusyFlag或Lock (上)
我们首先开发一个BusyFlag的类,类似于C++中的Simaphore。
public
class
BusyFlag {
protected
Thread
busyflag =
null
;
protected
int
busycount = 0;
public
synchronized
void
getBusyFlag() {
while
(tryGetBusyFlag() ==
false
) {
try
{
wait();
}
catch
(
Exception
e) {}
}
}
private
synchronized
boolean
tryGetBusyFlag() {
if
(busyflag ==
null
) {
busyflag =
Thread
.currentThread();
busycount = 1;
return
true
;
}
if
(busyflag ==
Thread
.currentThread()) {
busycount++;
return
true
;
}
return
false
;
}
public
synchronized
void
freeBusyFlag() {
if
(getOwner()==
Thread
.currentThread()) {
busycount--;
if
(busycount==0) {
busyflag =
null
;
notify();
}
}
}
public
synchronized
Thread
getOwner() {
return
busyflag;
}
}
注:参考Scott Oaks & Henry Wong《Java Thread》
BusyFlag有3个公开方法:getBusyFlag, freeBusyFlag, getOwner,分别用于获取忙标志、释放忙标志和获取当前占用忙标志的线程。使用这个BusyFlag也非常地简单,只需要在需要锁定的地方,调用BusyFlag的getBusyFlag(),在对锁定的资源使用完毕时,再调用改BusyFlag的freeBusyFlag()即可。下面我们开始改造上篇中的Account和ATM类,并应用BusyFlag工具类使得同时只有一个线程能够访问同一个账户的目标得以实现。首先,要改造Account类,在Account中内置了一个BusyFlag对象,并通过此标志对象对Account进行锁定和解锁:
import
java.util.
Collections
;
import
java.util.
HashMap
;
import
java.util.
Map
;
class
Account {
String
name;
//float amount;
BusyFlag flag =
new
BusyFlag();
//使用一个Map模拟持久存储
static
Map
storage =
new
HashMap
();
static
{
storage.put(
"John"
,
new
Float
(1000.0f));
storage.put(
"Mike"
,
new
Float
(800.0f));
}
static
Map
accounts =
Collections
.synchronizedMap(
new
HashMap
());
private
Account(
String
name) {
this
.name = name;
//this.amount = ((Float)storage.get(name)).floatValue();
}
public
synchronized
static
Account getAccount (
String
name) {
if
(accounts.get(name) ==
null
)
accounts.put(name,
new
Account(name));
return
(Account) accounts.get(name);
}
public
synchronized
void
deposit(
float
amt) {
float
amount = ((
Float
)storage.get(name)).floatValue();
storage.put(name,
new
Float
(amount + amt));
}
public
synchronized
void
withdraw(
float
amt)
throws
InsufficientBalanceException {
float
amount = ((
Float
)storage.get(name)).floatValue();
if
(amount >= amt)
amount -= amt;
else
throw
new
InsufficientBalanceException();
storage.put(name,
new
Float
(amount));
}
public
float
getBalance() {
float
amount = ((
Float
)storage.get(name)).floatValue();
return
amount;
}
public
void
lock() {
flag.getBusyFlag();
}
public
void
unlock() {
flag.freeBusyFlag();
}
}
新的Account提供了两个用于锁定的方法:lock()和unlock(),供Account对象的客户端在需要时锁定Account和解锁Account,Account通过委托给BusyFlag来提供这个机制。另外,大家也发现了,新的Account中提供了对Account对象的缓存,同时去除了public的构造方法,改为使用一个静态工厂方法供用户获取Account的实例,这样做也是有必要的,因为我们希望所有的ATM机同时只能有一个能够对同一个Account进行操作,我们在Account上的锁定是对一个特定Account对象进行加锁,如果多个ATM同时实例化多个同一个user的Account对象,那么仍然可以同时操作同一个账户。所以,要使用这种机制就必须保证Account对象在系统中的唯一性,所以,这儿使用一个Account的缓存,并将Account的构造方法变为私有的。你也可以说,通过在Account类锁上进行同步,即将Account中的BusyFlag对象声明为static的,但这样就使同时只能有一台ATM机进行操作了。这样,在一台ATM机在操作时,全市其它的所有的ATM机都必须等待。
另外必须注意的一点是:Account中的getAccount()方法必须同步,否则,将有可能生成多个Account对象,因为可能多个线程同时到达这个方法,并监测到accounts中没有“John”的Account实例,从而实例化多个John的Account实例。s
ATM类只需作少量改动,在login方法中锁定Account,在logout方法中解锁:
public
class
ATM {
Account acc;
//作为演示,省略了密码验证
public
synchronized
boolean
login(
String
name) {
if
(acc !=
null
)
throw
new
IllegalArgumentException
(
"Already logged in!"
);
acc = Account.getAccount(name);
acc.lock();
return
true
;
}
public
void
deposit(
float
amt) {
acc.deposit(amt);
}
public
void
withdraw(
float
amt)
throws
InsufficientBalanceException {
acc.withdraw(amt);
}
public
float
getBalance() {
return
acc.getBalance();
}
public
synchronized
void
logout () {
acc.unlock();
acc =
null
;
}
}
ATMTester类不需要做任何修改即可同样运行,同时保证同一个Account同时只能由一个ATM进行操作。解决了上篇提到的多个ATM同时对同一个Account进行操作造成的问题。
在最新的Doug Lea的util.concurrent工具包中(现处于JSR166)提供了类似的并发实用类:ReentrantLock,它实现了java .util.concurrent.locks.Lock接口(将在JDK1.5中发布),它的作用也类似于我们这儿的BusyFlag,实现机制、使用方法也相似。但这是一个工业强度的可重入锁的实现类。在ReentrantLock的API文档中有它的使用示例:
Lock l = ...;
l.lock();
try
{
// access the resource protected by this lock
}
finally
{
l.unlock();
}
关于Doug Lea的util.concurrent包的详细信息请参见:
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
--------=====全文完====---------
JSP虚拟主机,JSP空间,JSP主机,JAVA虚拟主机,JAVA空间
免费vps试用,vps在线开通,linux vps
tomcat web hosting
jsp主机
支持月付的JSP主机
Copyright © 2002-2012 JSPCN.net. All rights reserved.
JSP中文网 备案号:粤ICP备09171188号
成都恒海科技发展有限公司 成都市一环路南二段6号新瑞楼三楼8号