簡體   English   中英

Java線程同步-以正確的順序打印數字

[英]Java Thread synchronization - printing out numbers in right order

我正在學習如何在Java中使用線程,我需要一些建議。

我想在0..50的標准輸出數字上打印使用三個線程完成的線程的名稱。

我有兩個類-實現Runnable的Counter 和創建並運行線程的Main類 計數器具有在線程之間共享的變量c

我的想法是,我將c加1,然后在當前線程上調用yield() ,以便其他線程也可以這樣做。 重復此操作,直到c達到50。

但這不起作用,數字打印順序錯誤。 我該如何解決?

public class Counter implements Runnable {

Thread t1;
private int c = -1;

public Counter() {
}

public Counter(String name) {
    t1 = new Thread(this, name);
    t1.start();
}

@Override
public void run() {
    while (c < 50) {
        increment();
        Thread.yield();
    }
}

public void increment() {
    if (c < 50) {
        c++;
        System.out.println(Thread.currentThread().getName() + ": " + c);
    }
}
}

public class Main {

public static void main(String[] args) throws IllegalThreadStateException {
    Counter c1 = new Counter();
    Thread t1 = new Thread(c1, "Thread 1");
    Thread t2 = new Thread(c1, "Thread 2");
    Thread t3 = new Thread(c1, "Thread 3");

    t1.start();
    t2.start();
    t3.start();

}

編輯:最終我以這種方式解決了它。 謝謝所有幫助我艱難地開始多線程工作的人。

import java.util.concurrent.atomic.AtomicInteger;

public class Counter2 implements Runnable {

// you could also use simple int
private AtomicInteger c = new AtomicInteger(-1);
private static final Object syncObject = new Object();

public Counter2() {
}

@Override
public void run() {
    while (c.get() < 50) {
        synchronized (syncObject) {
            if (c.get() < 50) {
                System.out.println(Thread.currentThread().getName() + ": " + c.incrementAndGet());
            }
        }
    }
}    
}

在帶有特殊靜態對象的方法增量中使用同步部分。

private static final Object syncObj = new Object();

public void increment()
{
  syncrhonized( syncObj )
  {
   c++;
   System.out.println(c);
  }
}

或通過其聲明使此方法同步。

但是將實際數據存儲在線程對象中是錯誤的想法。 線程應該只使用共享對象進行操作,而不要存儲它們。\\實際上我不明白為什么要在其中啟動線程

使increment()同步,以防止其他線程同時進入方法。

yield()結合使用,您應該能夠使另一個線程打印下一個數字(並非總是如此,因為系統可能會再次恢復調用yield的線程-請參閱Ingo的答案-,但順序應相同)。

synchronized increment()意味着,如果另一個線程通過輸入方法已經獲取了鎖,則試圖在同一對象上輸入該方法的任何線程都必須等待。

引用javadoc Thread.yield(),我強調:

public static void yield()

給調度程序的提示是當前線程願意放棄當前使用的處理器。 調度程序可以隨意忽略此提示

...

很少適合使用此方法。

是的,您的代碼無效。 Thread#yield()不會以您期望的方式控制線程調度程序。 我很好奇您會得到什么結果。您可能會得到重復的數字,有些數字會有些混亂。

您可以使用原子整數,該整數應刪除所有重復項。 但是由於print語句不是原子的。 您仍然可以不按順序打印結果。 因此,您可能應該僅同步增量方法。 另外,您實際上並不需要產量,所以將其丟棄。

如果問題的目的是從線程1到線程2再到線程3再回到線程1,依此類推,那么結果是

Thread 1:0
Thread 2:1
Thread 3:2
Thread 1:3
Thread 2:4
Thread 3:5
Thread 1:6
Thread 2:7
....

然后,您需要鎖定增量方法,並使用wait和notifyAll。 等待將導致其他線程停止處理,直到當前線程通知它們再次啟動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM