论坛首页 入门技术论坛

Several approaches to solve deadlock

浏览 1309 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-11-10   最后修改:2010-11-10
This is an example from the official concurrency tutorial.
http://download.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

The reason for the deadlock here is that there are two sync methods
		public synchronized void bow(Friend bower) {
			System.out.format("%s: %s has bowed to me!%n", this.name, bower
					.getName());
			bower.bowBack(this);
		}

		public synchronized void bowBack(Friend bower) {
			System.out.format("%s: %s has bowed back to me!%n", this.name,
					bower.getName());
		}

Say, you have two objects a and b, you call them from thread1 a.bow(b) and from thread2 b.bow(a). When a holds its own lock finished printing and trying to grab b's lock(by calling b.bowBack(a)), b will be holding its own lock, finished printing and trying to grab a's lock. Here comes the deadlock.

How to solve it?
A. Use the same lock for object a and b so that they can have exclusive access to bow(). Previous deadlock situation happens because there is no exclusive access to bow(). To do this, you can pass an explicit lock to both a and b(of course add one constructor for the lock), or you can simply use Class as the lock because both a and b share the same class object.
        public void bow(Friend bower) {    		
    		synchronized (this.getClass()) {
    			System.out.format("[%s] %s: %s has bowed to me!%n", Thread.currentThread().getName(),this.name, bower.getName());
    			bower.bowBack(this);
    		}
        }

        public void bowBack(Friend bower) {
        	synchronized (this.getClass()) {
            System.out.format("[%s] %s: %s has bowed back to me!%n", Thread.currentThread().getName(), 
                    this.name, bower.getName());
        	}
        }


B. You can maintain a universal order for getting locks so that no matter which thread access bow(), simultaneously they can only access different parts of it.
        public void bow(Friend bower) {
        	int hashThis = System.identityHashCode(this);
        	int hashBower = System.identityHashCode(bower);
        	
        	if (hashThis < hashBower) {
        		synchronized(this) {
        			synchronized(bower) {
        				System.out.printf("[%s]: this: %d, bower: %d\n", Thread.currentThread().getName(), hashThis, hashBower);
        				System.out.printf("[%s] %s bow to %s\n", Thread.currentThread().getName(), this.getName(), bower.getName());
        				bower.bowBack(this);
        			}
        			
        		}
        	} else if (hashThis > hashBower) {
        		synchronized(bower) {
        			synchronized(this) {
        				System.out.printf("[%s]222 %s bow to %s\n", Thread.currentThread().getName(), this.getName(), bower.getName());
        				bower.bowBack(this);
        			}
        		}
        	} else {
        		synchronized (getClass()) {
        			System.out.printf("[%s]333 %s bow to %s", Thread.currentThread().getName(), this.getName(), bower.getName());
        			bower.bowBack(this);
        		}
        	}
        }


C. Use explicit Lock, this is the approach that is provided by this official tutorial, which should achieve the best performance at practice. One of the advantages is that the tryLock() method can grab the lock or returns false if the lock is held by other threads.
check it out. http://download.oracle.com/javase/tutorial/essential/concurrency/newlocks.html
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics