JSPCN主页
|
JSP空间
|
网站制作
|
JSP下载
|
JSP论坛
|
JSP教程
|
关于JSPCN
|
联系我们
做最专业的JSP中文网站
当前位置
:
首页
--
JAVA技术
--
JAVA线程
文章搜索:
关键字
标题
JSP中文网内容管理系统(JCMS)
JSP虚拟主机
网络笔记本
网摘,图片,笔记收藏
虚拟服务器
JSPCN文章目录分类
JSP配置
[
219
]
JSP基础
[
136
]
中文问题
[
69
]
上传问题
[
27
]
JAVABEAN
[
46
]
数据库
[
212
]
文件操作
[
126
]
图片声音
[
17
]
JSP其他
[
57
]
时间相关
[
16
]
JAVAMAIL
[
72
]
STRUTS
[
144
]
开发工具
[
28
]
教程系列
[
157
]
JSP实例
[
89
]
JAVA基础
[
421
]
APPLET
[
78
]
JAVA网络
[
179
]
Applica
[
115
]
Servlet
[
98
]
XML
[
163
]
J2ME
[
257
]
J2EE
[
374
]
考试相关
[
63
]
JAVA线程
[
90
]
EJB
[
261
]
Swing
[
26
]
Java API
[
141
]
声音图片
[
28
]
异常处理
[
33
]
JAVA实例
[
290
]
JAVA类
[
139
]
SUN
[
89
]
Hibernate
[
6
]
JMX
[
8
]
Spring
[
34
]
本版推荐文章
用Java实现多线程服务器程序
当主线程崩溃而其它线程继续运行时发生什么?
采用多线程制作动画
什么是线程?
派生线程类
线程基础
线程基础(第二部分)Java线程的缺陷和副作用几解决办法
Java中利用管道实现线程间的通讯
Java程序中的多线程
编写多线程的Java应用程序-如何避免当前编程中最常见的问题
Java线程控制的图像分割与合成
使用JAVA建立稳定的多线程服务器
Java多线程程序设计入门
Java线程的讨论与应用
多线程程序设计
扫描整个网段的多线程程序
关于多线程
线程池的介绍及简单实现
线程池与工作队列
Java技术:使您轻松地进行多线程应用程序编程
本版热点文章
java线程编程(一):线程基础
什么是线程?
java多线程数据库操作
彻底明白Java的多线程-线程间的通信
Java多线程程序设计入门
创建Java中的线程池
线程池的介绍及简单实现
JAVA 的多线程浅析
关于线程的讲解(出自Java原著)
用Java实现多线程服务器程序
再论Java Swing线程
Java技术:使您轻松地进行多线程应用程序编程
转-关于多线程
线程基础
Java程序中的多线程
Java调试教程--多线程调试
深入浅出Java多线程程序设计.doc
线程基础(第二部分)Java线程的缺陷和副作用几解决办法
解析Java的多线程机制
Java中利用管道实现线程间的通讯
相关文章链接
Java多线程同步教程--BusyFlag或Lock (下)
作者: 文章来源:
访问次数:11次 加入时间: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
--------=====全文完====---------
Copyright © 2002-2005
JSP
CN.net. All rights reserved.
JSP中文网 备案序号:蜀ICP备05001583号
成都恒海科技发展有限公司 成都市一环路南二段6号新瑞楼三楼8号