这里错了
try
{
currentThread.wait(timeout);
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}改成 try
{
currentThread.sleep(timeout);
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
try
{
currentThread.wait(timeout);
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}改成 try
{
currentThread.sleep(timeout);
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
一个线程可以有四种状态:
(1) 新(New):线程对象已经创建,但尚未启动,所以不可运行。
(2) 可运行(Runnable):意味着一旦时间分片机制有空闲的CPU周期提供给一个线程,那个线程便可立即开始运行。因此,线程可能在、也可能不在运行当中,但一旦条件许可,没有什么能阻止它的运行——它既没有“死”掉,也未被“堵塞”。
(3) 死(Dead):从自己的run()方法中返回后,一个线程便已“死”掉。亦可调用stop()令其死掉,但会产生一个违例——属于Error的一个子类(也就是说,我们通常不捕获它)。记住一个违例的“掷”出应当是一个特殊事件,而不是正常程序运行的一部分。所以不建议你使用stop()(在Java 1.2则是坚决反对)。另外还有一个destroy()方法(它永远不会实现),应该尽可能地避免调用它,因为它非常武断,根本不会解除对象的锁定。
(4) 堵塞(Blocked):线程可以运行,但有某种东西阻碍了它。若线程处于堵塞状态,调度机制可以简单地跳过它,不给它分配任何CPU时间。除非线程再次进入“可运行”状态,否则不会采取任何操作。14.3.1 为何会堵塞
堵塞状态是前述四种状态中最有趣的,值得我们作进一步的探讨。线程被堵塞可能是由下述五方面的原因造成的:
(1) 调用sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。
(2) 用suspend()暂停了线程的执行。除非线程收到resume()消息,否则不会返回“可运行”状态。
(3) 用wait()暂停了线程的执行。除非线程收到nofify()或者notifyAll()消息,否则不会变成“可运行”(是的,这看起来同原因2非常相象,但有一个明显的区别是我们马上要揭示的)。
(4) 线程正在等候一些IO(输入输出)操作完成。
(5) 线程试图调用另一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。亦可调用yield()(Thread类的一个方法)自动放弃CPU,以便其他线程能够运行。然而,假如调度机制觉得我们的线程已拥有足够的时间,并跳转到另一个线程,就会发生同样的事情。也就是说,没有什么能防止调度机制重新启动我们的线程。线程被堵塞后,便有一些原因造成它不能继续运行。
不管你的逻辑如何。
当你要wait的时候,你必须还在synchronized这个对象。
比如说,你要obj.wait(), 必须
synchronized(obj){obj.wait();}
thread.wait()也不是让thread线程等待,它是让你的当前线程等待thread的信号。总而言之,建议还是好好看看jdk的文档吧。
既然如此,那个等待线程还等个啥啊?不是单相思嘛?直接throw exception不就完了?
除非你还有其它的线程去减小计数。
thread也就是一个Object.
看一看Object类的文档就都明白啦。只有让当前线程等待,没有让一个Thread对象等待这码事。
void deref();
?
我这里有一个生产者-消费者的代码,你照自己的需求改改应该就能用:
public interface Channel{
public Object get()throws BufferEmptyException;
//non blocking consume
public void put(Object obj)throws BufferFullException;
//non blocking produce
public Object consume()
throws InterruptedException;
//wait indefinitely until available
public void produce(Object obj)
throws InterruptedException;
//wait indefinitely until not full
public Object consume(long timeout)
throws ResourceTimeOutException, InterruptedException;
public void produce(Object val, long timeout)
throws ResourceTimeOutException, InterruptedException;
public Object peek()throws BufferEmptyException;
//non blocking peek
public boolean isEmpty();
public boolean isFull();
public void close();
public void open();
public boolean isClosed();
public void closeSource();
public void closeSink();
public void openSource();
public void openSink();
public boolean isSourceClosed();
public boolean isSinkClosed();
}
//ChannelBuffer used here does not need to be synchronized.
//the order of acquiring locks are important to avoid deadlock.
//our order is always rlock->wlock->thislock
public final class ChannelImpl implements Channel{
private final Object rlock = new Object();
private final Object wlock = new Object();
private final ChannelBuffer buf;
private boolean srcoff;
private boolean sinkoff;
public final synchronized void open(){
srcoff = false;
sinkoff = false;
}
public final synchronized void openSource(){
srcoff = false;
}
public final synchronized void openSink(){
sinkoff = false;
}
public final synchronized boolean isClosed(){
return srcoff&&sinkoff;
}
public final void close(){
synchronized(rlock){
synchronized(wlock){
synchronized(this){
if(!srcoff){
srcoff = true;
rlock.notifyAll();
}
if(!sinkoff){
sinkoff = true;
wlock.notifyAll();
}
}
}
}
}
public final void closeSource(){
synchronized(rlock){
synchronized(this){
if(!srcoff){
srcoff = true;
rlock.notifyAll();
}
}
}
}
public final void closeSink(){
synchronized(wlock){
synchronized(this){
if(!sinkoff){
sinkoff = true;
wlock.notifyAll();
}
}
}
} public final synchronized boolean isSourceClosed(){
return srcoff;
}
public final synchronized boolean isSinkClosed(){
return sinkoff;
} private final synchronized Object _get()
throws BufferEmptyException{
if(srcoff)throw new TargetClosedException();
return buf.get();
}
private final synchronized void _put(Object val)
throws BufferFullException{
if(sinkoff)throw new TargetClosedException();
buf.put(val);
}
public final Object get()
throws BufferEmptyException{
final Object val = _get();
synchronized(wlock){
wlock.notify();
}
return val;
} public final void put(Object obj)
throws BufferFullException{
_put(obj);
synchronized(rlock){
rlock.notify();
}
}
public final synchronized Object peek()
throws BufferEmptyException{
return buf.peek();
}
public final synchronized boolean isEmpty(){
return buf.isEmpty();
}
public final synchronized boolean isFull(){
return buf.isFull();
}
public final Object consume()
throws InterruptedException{
final Object val = _consume();
synchronized(wlock){
wlock.notify();
}
return val;
}
public final void produce(Object obj)
throws InterruptedException{
_produce(obj);
synchronized(rlock){
rlock.notify();
}
}
public final Object consume(long timeout)
throws InterruptedException, ResourceTimeOutException{
if(timeout<=0)
throw new IllegalArgumentException("timeout should be greater than 0");
final Object val = _consume(timeout);
synchronized(wlock){
wlock.notify();
}
return val;
}
public final void produce(Object obj, long timeout)
throws InterruptedException, ResourceTimeOutException{
if(timeout<=0)
throw new IllegalArgumentException("timeout should be greater than 0");
_produce(obj, timeout);
synchronized(rlock){
rlock.notify();
}
}
private final Object _consume()
throws InterruptedException{
synchronized(rlock){
for(;;){
try{
return _get();
}
catch(BufferEmptyException e){
rlock.wait();
}
}
}
} private final void _produce(Object val)
throws InterruptedException{
synchronized(wlock){
for(;;){
try{
_put(val);
return;
}
catch(BufferFullException e){
wlock.wait();
}
}
}
}
private final Object _consume(long timeout)
throws InterruptedException, ResourceTimeOutException{
synchronized(rlock){
for(long starttime = System.currentTimeMillis();;){
try{
return _get();
}
catch(BufferEmptyException e){
rlock.wait(timeout);
if((System.currentTimeMillis() - starttime) >= timeout){
throw new edu.my.util.res.ResourceTimeOutException();
}
}
}
}
} private final void _produce(Object val, long timeout)
throws InterruptedException, ResourceTimeOutException{
synchronized(wlock){
for(long starttime = System.currentTimeMillis();;){
try{
_put(val);
return;
}
catch(BufferFullException e){
wlock.wait(timeout);
if((System.currentTimeMillis() - starttime) >= timeout){
throw new edu.my.util.res.ResourceTimeOutException();
}
}
}
}
} private ChannelImpl(ChannelBuffer buf, boolean srcoff, boolean sinkoff){
this.buf = buf;
this.srcoff = srcoff;
this.sinkoff = sinkoff;
}
public static ChannelOwner instance(ChannelBuffer buf){
return new ChannelImpl(buf, false, false);
}
}public interface ChannelBuffer{
public Object get()throws BufferEmptyException;
//non blocking consume
public void put(Object obj)throws BufferFullException;
//non blocking produce
public Object peek()throws BufferEmptyException;
//non blocking peek
public boolean isEmpty();
public boolean isFull();
}代码并不完全。但主要的都在了。
客户怎么释放一个Singleton对象呢?靠finalize()吗?finalize可能根本不运行。
除非你要求客户显式调用个close()函数。但那样,对客户可是个负担。万一客户忘记调用close()就坏了。
而且,对一个一般的小对象,限制实例个数并没什么好处。它又不占什么资源。
从需求来看,你需要让用户调用一个close()函数。
而且,也没有要同步等待甚至线程安全的逻辑。
这不是很简单?class Singleton{
private final Home home;
public void close(){
home.deref();
//释放其它昂贵的资源。
}
}
class SingletonHome implements Home{
public void deref(){--ref;}
public Singleton get(){if(ref>=max)throw new TooManyInstancesException(); ++ref; return new Singleton(this);}
private final int max;
private int ref;
}然后就
SingletonHome home = new SingletonHome();
Singleton s1 = home.get();home.get();
Singleton s2 = home.get();
s1.close();
s2.close();
你的需求里根本没有线程安全啊。再说,要安全还不容易?加上synchronized不就完了?
public class SingletonPattern2
{
public static void main(String[] args)
{
Singleton2 s = Singleton2.newInstance();
new OpenThread("open thread").start();
new CloseThread("close thread").start();
}
}
final class OpenThread extends Thread
{
public OpenThread(String str)
{
super(str);
}
public void run()
{
Singleton2 s = Singleton2.newInstance();
int count = 0;
while (count < 10)
{
s.open();
count ++;
}
}
}
final class CloseThread extends Thread
{
public CloseThread(String str)
{
super(str);
}
public void run()
{
Singleton2 s = Singleton2.newInstance();
int count = 0;
while (count < 10)
{
s.close();
count ++;
}
}
}
final class Singleton2
{
public static Singleton2 instance = new Singleton2();
public final int maxInstances = 10;
public int currentInstances;
public static Singleton2 newInstance()
{
if ( null == instance )
{
return new Singleton2();
}
return instance;
}
private Singleton2()
{
}
public synchronized void open() throws ReferenceOverAgeException
{
if ( currentInstances < maxInstances )
{
++ currentInstances;
System.out.println("current references are "+currentInstances);
}
else
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
notifyAll();
}
public synchronized void close() throws ReferenceShortAgeException
{
if ( currentInstances > 0 )
{
-- currentInstances;
System.out.println("current references are "+currentInstances);
}
else
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
notifyAll();
}
}
public void run()
{
Singleton2 s = Singleton2.newInstance();
int count = 0;
while (count < 10)
{
s.close();
count ++;
}
}count < 10中,当10改成了大于instancesMax的数值后,程序就会出现死锁
如何处理才能避免这个死锁,而且又不影响程序的运行(也就是说不允许open一次,然后必须close一次这样的控制。open和close必须是自由的)