2017-05-27 46 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^^^^"); 
     } 
    } 
}