2016-07-30 63 views
2

我在syncCmd功能同步塊:迫不及待情況下同步部分被佔用

public Object Sync = new Object(); 
public void syncCmd(String controlCmd) { 
    synchronized(Sync) { 

     ... 
    } 
} 

我需要添加一些邏輯的情況下,如果一個線程已經佔據Sync,並做其工作。在這種情況下,我想向系統報告"too busy"而不是排隊。知道是否有人佔用Sync部分的最佳方法是什麼?如何知道本節中有多少線程正在等待?一切都在Java 1.4.

+0

您好,雖然[this](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)可能無法回答您的問題,但請相信它仍然與您的情況相關(JDK 1.4 ),除非您已經將其視爲您實施的一部分。 –

+0

如果程序中的任何線程可以佔用互斥鎖的時間太長,以至於其他線程無法等待它,那麼這是一個正在重新設計的算法。 –

回答

2

看看Lock接口及其實現ReentrantLock。它可以讓你使用tryLock()方法,包括允許等待一段時間的變種,如果資源已經被鎖定:

private ReentrantLock lock = new ReentrantLock(); 

public void syncCmd(String controlCmd) { 
    if (lock.tryLock()) { 
     try { 
      // Use your synchronized resource here 
     } finally { 
      lock.unlock(); 
     } 
    } else { 
     // Failed to lock 
    } 
} 

Java 1.4中,不幸的是,沒有java.util.concurrency包,我覺得你最好的選擇是通過​​手段和雙重檢查,以實現相同的邏輯:

public class Lock { 
    private final Object lock = new Object(); 
    private volatile boolean locked = false; 

    public boolean tryLock() { 
     if (!locked) { 
      synchronized (lock) { 
       if (!locked) { 
        locked = true; 
        return true; 
       } 
      } 
     } 
     return false; 
    } 

    public void unlock() { 
     synchronized (lock) { 
      locked = false; 
     } 
    } 
} 

它不會工作快ReentrantLock使用CAS循環在現代JVM處理器指令的支持,但它會做的工作。

此實現也是不可重入的,您可以擴展它以跟蹤鎖定線程並在需要再次進入時鎖定計數。

重要更新: @Stephen C在Java 1.4中提出了一個很好的觀點,即double check is broken,並且總是要牢記這一點。但也有例外。例如,簡單的基本類型。所以,我認爲它會在這個特定的情況下起作用。欲瞭解更多詳情,請查看"Double-Checked Locking is Broken" Declaration

+0

看起來不錯,但是它自java 1.5 – vico

+0

@羅曼,我同意我在這裏選擇了錯誤的措辭。它不必使用,我會編輯評論。這取決於所選擇的公平政策,但總的來說,它獨自行事。 –

+0

@vico,你說得對,我已經擴大了我的答案。 –

1

同步塊/方法和原語互斥體在Java中無法實現。

但是,如果您改用Lockjavadoc),則可以使用tryLock以永不阻止或僅在有限的時間內阻止。

例子:

Lock l = new ReentrantLock(); 
if (l.tryLock()) { 
    try { 
     // access the resource protected by this lock 
    } finally { 
      l.unlock(); 
    } 
else { 
    // report "too busy" 
} 

但是請注意,它用「嘗試......終於」並明確unlock()呼籲確保鎖被釋放始終是必不可少的。 (與​​構造不同,後者自動爲您處理。)

在Java 1.5之前,我沒有在純Java中知道的解決方案。本地代碼欺騙可能是可能的,但我不知道如何。


你/你的管理應該尋找到溝的Java 1.4對貴公司產品的支持,並從任何依賴於它的上面第三方產品遷移走。 Java 1.5本身在很多年前就已經發布了。實際上,Java 1.8之前的所有版本都已經EOL;請參閱Oracle Java SE Support Roadmap文檔。

0

試試這個(兩個班 - 執行人和Tracker):

執行人:

package com.example.so.jdk1_4.synch; 

import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 
import java.util.Random; 


/** 
* <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p> 
* @author Ravindra HV 
*/ 
public class InUseExample { 

    public synchronized void execute(String command) { 

     InUseTracker.obtainClassInstance().setInuse(true); 

     try { 
      System.out.println("Executing :"+command); 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     }// do work 

     InUseTracker.obtainClassInstance().setInuse(false); 
    } 


    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     System.out.println("Start :"+new Date()); 
     testInUseExample(); 
     System.out.println("Final wait count :"+InUseTracker.obtainClassInstance().waitCount()); 
     System.out.println("End :"+new Date()); 
    } 


    private static void testInUseExample() { 
     final InUseExample inUseExample = new InUseExample(); 

     Runnable runnable = new Runnable() { 
      @Override 
      public void run() { 

       try { 
        InUseTracker.obtainClassInstance().incrementWaitCount(); 
        while(true) { 
         if(InUseTracker.obtainClassInstance().isInuse() == false) { // reduces the chances of this thread going to a block mode.. 
          inUseExample.execute(Thread.currentThread().getName()); 
          break; 
         } 
         else { 
          try { 
           Random random = new Random(); 
           String message = Thread.currentThread().getName()+" - block in use by :"+InUseTracker.obtainClassInstance().getInUseBy(); 
           message = message+" "+". Wait Count :"+InUseTracker.obtainClassInstance().waitCount(); 
           System.out.println(message); 
           Thread.sleep(random.nextInt(1000)); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 

         } 
        } 

       } catch (Exception e) { 
        e.printStackTrace(); 
       } finally { 
        InUseTracker.obtainClassInstance().decrementWaitCount(); 
       } 

      } 
     }; 

     int threadCount = 10; 
     List<Thread> threadPoolTemp = new ArrayList<Thread>(); 
     for(int i=0;i<threadCount;i++) { 
      Thread thread = new Thread(runnable); 
      threadPoolTemp.add(thread); 
     } 

     for (Thread thread : threadPoolTemp) { 
      thread.start(); 
     } 

     for (Thread thread : threadPoolTemp) { 
      try { 
       thread.join(); // wait until all threads have executed.. 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 



} 

追蹤:

package com.example.so.jdk1_4.synch; 

/** 
* <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p> 
* @author Ravindra HV 
*/ 
public class InUseTracker { 

    private boolean inuse; 
    private int waitCount; 
    private String inUseBy; 

    private static InUseTracker DEFAULT_INSTANCE = new InUseTracker(); 

    private InUseTracker() { 
    } 

    public static InUseTracker obtainClassInstance() { 
     return DEFAULT_INSTANCE; 
    } 


    public synchronized boolean isInuse() { 
     return inuse; 
    } 

    public synchronized void setInuse(boolean inuse) { 
     this.inuse = inuse; 
     if(inuse) { 
      setInUseBy(Thread.currentThread().getName()); 
     } 
     else { 
      setInUseBy(""); 
     } 

    } 

    private void setInUseBy(String inUseBy) { 
     this.inUseBy = inUseBy; 
    } 

    public synchronized String getInUseBy() { 
     return inUseBy; 
    } 

    public synchronized void incrementWaitCount() { 
     waitCount++; 
    } 

    public synchronized void decrementWaitCount() { 
     waitCount--; 
    } 

    public synchronized int waitCount() { 
     return waitCount; 
    } 

} 

PS:猜猜你必須移動

InUseTracker.obtainClassInstance().setInuse(false); 

範圍內最後如果或酌情。

1

上述兩個答案談到了java.util.concurrent.locks.ReentrantLock,但它在Java 1.4中不存在。

太糟糕了,太難過了嗎?

不!如果系統庫和第三方庫不向您提供您想要的內容,請自行編寫!

下面的代碼做你要求的,絕對沒有更多。我個人不會在沒有首先添加一些功能的情況下使用它,這些功能會使它更易於使用,更易於測試,並且最重要的是,更加簡單。

我只是提供給你作爲開始的例子。

public class ExtremelySimplisticNonReentrantLock { 
    boolean isLocked = false; 

    /** 
    * @return true if the lock was acquired, false otherwise. 
    */ 
    public synchronized boolean tryToAcquire() { 
     if (isLocked) { 
      return false; 
     } 
     isLocked = true; 
     return true; 
    } 

    public synchronized void release() { 
     lsLocked = false; 
    } 
} 

分享和享受!