2016-10-13 8 views
0

Я пытаюсь написать небольшой фрагмент кода для блокировки и разблокировки блока кода. в acquire_lock и RELEASE_LOCK функции, как показано ниже:java многопотоковая блокировка не работает

public static void acquire_lock(long timestamp) { 
    synchronized(operations) { 
     // put the timestamp into queue 
     operations.add(timestamp); 
     // check if the head of queue is current timestamp, if not, 
     // this means there are some other operations ahead of current one 
     // so current operation has to wait 
     while (operations.peek() != timestamp) { 
      try { 
       operations.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

public static void release_lock() { 
    synchronized(operations) { 
     // poll the finished operation out of queue 
     // and wake up all waiting operations 
     operations.poll(); 
     operations.notifyAll(); 
    } 
} 

Но когда я ставлю этот код в тестовой среде, она не всегда работает хорошо, весь тестовый код, как показано ниже:

public class AcquireLockNotWork { 

static int balance = 0; 
static PriorityQueue<Long> operations = new PriorityQueue<Long>(); 

// withdraw money from balance 
public static void withdraw(final int amt) { 
    // get system time 
    Long timestamp = System.nanoTime(); 
    Thread t = new Thread(new Runnable() { 
     public void run() { 
      // try to use acquire_lock to lock this piece of code 
      acquire_lock(timestamp); 
      try {  
       Thread.sleep(500); 
       int holdings = balance; 
       balance = holdings - amt; 
       System.out.println("Withdrew " + amt + " from funds. Now at " + balance); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       release_lock(); 
      }  
     } 
    }); 
    t.start(); 
} 

//put money into banlance 
public static void deposit(int amt) { 
    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
      Long timestamp = System.nanoTime(); 
      acquire_lock(timestamp); 
      int holdings = balance; 
      balance = holdings + amt; 
      System.out.println("deposit " + amt + ", balance: " + balance); 
      release_lock(); 
     } 
    }); 
    t1.start(); 
} 

public static void acquire_lock(long timestamp) { 
    synchronized(operations) { 
     // put the timestamp into queue 
     operations.add(timestamp); 
     // check if the head of queue is current timestamp, if not, 
     // this means there are some other operations ahead of current one 
     // so current operation has to wait 
     while (operations.peek() != timestamp) { 
      try { 
       operations.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

public static void release_lock() { 
    synchronized(operations) { 
     // poll the finished operation out of queue 
     // and wake up all waiting operations 
     operations.poll(); 
     operations.notifyAll(); 
    } 
} 

public static void test1() { 
    balance = 0; 
    deposit(2000); 
    withdraw(500); 
    withdraw(1000); 
} 

public static void main(String[] args) { 
    test1(); 
} 
} 

для небольшого количества раз, то результат будет выглядеть следующим образом:

deposit 2000, balance: 2000 
Withdrew 500 from funds. Now at 500 
Withdrew 1000 from funds. Now at 500 

, что означает, что acquire_lock и RELEASE_LOCK фу nction не работает. Кажется, что последние два потока (сняли 500 и сняли 1000) вошли в блок между gets_lock() и release_lock() одновременно, и это не то, что я хочу. Так что же случилось с функцией purchase_lock и release_lock?

+0

Ваш код, похоже, полагается на 'System.nanoTime()' никогда не возвращая одно и то же значение более одного раза, но это поведение не гарантируется. Javadoc для 'System.nanoTime()' говорит: «Этот метод обеспечивает наносекундную точность, но не обязательно наносекундное разрешение (то есть, как часто изменяется значение)» –

ответ

0

Здесь очень сложно. Аномальный случай, потому что последняя нить сначала вводится в first_lock_lock. И когда предыдущий поток переходит в catch_lock, он не будет заблокирован, потому что код блокирует потоки на основе их метки времени. Таким образом, два потока идут к тому же защищенным кодовым областям.