2017-05-27 28 views
0

我做了這個簡單的線程減法程序。 它工作正常,但在輸出結束時,它會給出3個隨機值。我不知道如何防止這一點,任何想法? 我還必須計算每個線程減少了多少次計數器。有人可以幫助我嗎?Simple MultiThreads程序錯誤輸出

public class ThreadsExample implements Runnable { 
    static int counter = 100000; 

    static long time; 
    static long endtime; 
    static float finaltime; 
    static int value; 

    static void incrementCounter() { 
     System.out.println(Thread.currentThread().getName() + ": " + counter); 
     counter--;  
    } 

    @Override 
    public void run() {  
    time = System.nanoTime(); 
     while (counter >= 0) { 
      incrementCounter(); 
     } 
     endtime = System.nanoTime() - time; 
     finaltime = endtime; 

     System.out.println(finaltime/1000000000 + " sekundy"); 
    } 
    public static void main(String[] args) throws InterruptedException { 
     ThreadsExample threads = new ThreadsExample(); 
     Thread thread1 = new Thread(threads); 
     Thread thread2 = new Thread(threads); 
     Thread thread3 = new Thread(threads); 
     Thread thread4 = new Thread(threads); 

     thread1.start(); 
     thread2.start(); 
     thread3.start(); 
     thread4.start(); 

     if (counter <= 0) { 
      System.out.println("Thread 1,2,3,4^^^"); 
     } 
    } 
} 
+0

首先,您將ThreadExample的同一個實例傳遞給每個線程。這可能會導致一些內部狀態異常。嘗試爲每個線程構造函數創建一個新的ThreadsExample。它看起來像每個ThreadsExample將基本上同時停止,因爲「counter」是靜態的,並且所有實例都會在基本相同的確切時間檢測到「counter <0」。這是預期的嗎?或者你想讓每個線程管理自己的獨立計數器? – pacifier21

+0

你沒有任何形式的同步。因此,每個線程可能會讀取一些值'> 0'並減少'counter',這樣'counter'就會以某個值<<0結束。此外,每個線程都會將'finaltime'設置爲一個值,您在那裏有一個競爭條件。 – Turing85

回答

0

您正在經歷多線程編程的缺陷。 您可能遇到兩個問題。

  1. 你沒有申報揮發性counter,所以線程訪問可能會看不到它的電流值馬上
  2. 根據條件你都賺不到的原子更新(即計數器> = 0)。 您的線程1檢查counter >= 0可能是真的,那麼線程2個遞減計數器,那麼線程1個遞減太,因爲它認爲計數器> = 0

退房java.util.concurrent.atomic.AtomicInteger。 你可能想用它作爲counter

0

如果我正確理解您的問題,嘗試做了一些調整,像這樣:

// Need to import Lock to protect synchronized logic 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class ThreadsExample implements Runnable { 

    static int counter = 100000; 
    // Lock to help synchronize access to counter 
    static Lock lock = new ReentrantLock(); 

    // These should not be static - they should be local to each ThreadsExample 
    long time; 
    long endtime; 
    float finaltime; 
    // Didn't see where this was used, so I'm using to track mod count 
    int value; 

    // Doesn't need to be static 
    void incrementCounter() { 

     System.out.println(Thread.currentThread().getName() + ": " + counter); 
     counter--; 

    } 

    @Override 
    public void run() { 

     time = System.nanoTime(); 
     // Use this boolean to determine when to stop 
     boolean done = false; 
     while (!done) { 
      // Acquire the lock 
      lock.lock(); 
      try { 
       // Now that this thread owns the lock, it can check 
       // the counter without worrying about other threads 
       // making modifications 
       if (counter > 0) { 
        incrementCounter(); 
        // Increment the mod count (how many times this thread affected counter) 
        value++; 
       } else { 
        // We can stop here since counter is 0 or less 
        done = true; 
       } 
      } finally { 
       // Release the lock so other threads have a chance 
       lock.unlock(); 
      } 
     } 
     endtime = System.nanoTime() - time; 
     finaltime = endtime; 

     System.out.println(finaltime/1000000000 + " sekundy"); 
     // Print out the mod count 
     System.out.println(Thread.currentThread().getName() + " updated counter " + value + " times."); 

    } 

    public static void main(String[] args) throws InterruptedException { 
     // Create a new ThreadsExample for each Thread 
     // And give the threads readable names. 
     Thread thread1 = new Thread(new ThreadsExample(), "thread-1"); 
     Thread thread2 = new Thread(new ThreadsExample(), "thread-2"); 
     Thread thread3 = new Thread(new ThreadsExample(), "thread-3"); 
     Thread thread4 = new Thread(new ThreadsExample(), "thread-4"); 

     thread1.start(); 
     thread2.start(); 
     thread3.start(); 
     thread4.start(); 

     // Note: This will likely never get printed since it might take 
     // a few milliseconds for the other threads to "consume" the counter 
     if (counter <= 0) { 
      System.out.println("Thread 1,2,3,4^^^"); 
     } 
    } 
} 

我也建議給予ThreadsExample本地名稱變量,而不是使用Thread.currentThread()的getName()。 ,但這取決於你。

+0

是的,這就是我想要的,但看看控制檯的結束。當它達到0時,它給出3個隨機整數的輸出。 – Nexog

+0

我沒有看到3個隨機整數。這是我的控制檯輸出的結尾:8.759564 sekundy 線程4更新計數器22134次。 8.941281 sekundy thread-1 updated updated counter 25116次。 8.759831 sekundy 線程-3更新計數器32714次。 8.761887 sekundy thread-2 updated updated 20043 times。 – pacifier21

+0

我想我現在知道你在說什麼了。其他線程還沒有完成,他們正在打印輸出前報告一個非零計數器值,對吧?我將嘗試一種不同的方法,並且我會更新我的答案。 – pacifier21

0
public class ThreadsExample implements Runnable { 

    private static volatile int counter = 100000; // 10k 
    private int counterDecrements = 0; // zero decrements 

    // Doesn't need to be static, but should likely be synchronized 
    private void incrementCounter() { 

     System.out.println(Thread.currentThread().getName() + ": " + counter); 
     // counter--; 
     // ++counterDecrements; 

    } 

    @Override 
    public void run() { 

     long startTime, endTime, timeDiff; 

     startTime = System.currentTimeMillis(); 
     while (counter >= 0) { 
      incrementCounter(); // thread loop 
      --counter; 
      ++counterDecrements; 

     } 
     endTime = System.currentTimeMillis(); 
     timeDiff = startTime - endTime; // time diffrence is how long it took. 

     System.out.println((timeDiff/1000000000) + " sekundy"); 
     // Print out the mod count 
     System.out.println(Thread.currentThread().getName() + " Decremented counter " + counterDecrements + " times."); 

    } 

    public static void main(String[] args) throws InterruptedException { 
     // Create a new ThreadsExample for each Thread 
     // And give the threads readable names. 
     Thread thread1 = new Thread(new ThreadsExample(), "thread-1"); 
     Thread thread2 = new Thread(new ThreadsExample(), "thread-2"); 
     Thread thread3 = new Thread(new ThreadsExample(), "thread-3"); 
     Thread thread4 = new Thread(new ThreadsExample(), "thread-4"); 

     thread1.start(); 
     thread2.start(); 
     thread3.start(); 
     thread4.start(); 


     if (counter == 0) { 
      System.out.println("Thread 1,2,3,4^^^^"); 
     } 
    } 
}