[英]Java multithreading unexpected output
我正在嘗試在 Java 中學習多線程。 這是我寫的代碼:
public class SharedResources {
volatile private int sharedPar1;
volatile private String sharedPar2;
public SharedResources(Integer sharedPar1, String sharedPar2) {
synchronized (sharedPar1) {
this.sharedPar1 = sharedPar1;
}
synchronized (sharedPar2) {
this.sharedPar2 = sharedPar2;
}
}
public synchronized int getSharedPar1() {
return sharedPar1;
}
public synchronized void setSharedPar1(int sharedPar1) {
this.sharedPar1 = sharedPar1;
}
public synchronized String getSharedPar2() {
return sharedPar2;
}
public synchronized void setSharedPar2(String sharedPar2) {
this.sharedPar2 = sharedPar2;
}
}
上面這只是一個代表模擬共享資源的class。 兩個模擬線程類:
public class Task1 extends Thread {
volatile private SharedResources sharedResources;
public Task1(SharedResources sharedResources) {
this.sharedResources = sharedResources;
}
public SharedResources getSharedResources() {
return sharedResources;
}
public void setSharedResources(SharedResources sharedResources) {
this.sharedResources = sharedResources;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
sharedResources.setSharedPar1(sharedResources.getSharedPar1() + 1000);
sharedResources.setSharedPar2(sharedResources.getSharedPar2() + "c");
System.out.println("Task1, it. " + i + ". - Shared resources: " + sharedResources.getSharedPar1() + " and " + sharedResources.getSharedPar2());
}
}
}
任務 2:
public class Task2 extends Thread {
volatile private SharedResources sharedResources;
public Task2(SharedResources sharedResource) {
this.sharedResources = sharedResource;
}
public SharedResources getSharedResources() {
return sharedResources;
}
public void setSharedResources(SharedResources sharedResources) {
this.sharedResources = sharedResources;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
sharedResources.setSharedPar1(sharedResources.getSharedPar1() + 100);
sharedResources.setSharedPar2(sharedResources.getSharedPar2() + "b");
System.out.println("Task2, it. " + i + ". - Shared resources: " + sharedResources.getSharedPar1() + " and " + sharedResources.getSharedPar2());
}
}
}
現在,主要的function:
public static void main(String[] args) {
SharedResources sharedResource = new SharedResources(0, "");
Thread firstTask = new Task1(sharedResource);
Thread secondTask = new Task2(sharedResource);
firstTask.start();
secondTask.start();
for (int i = 0; i < 10; i++) {
System.out.println("Main thread! - Shared resources: " + sharedResource.getSharedPar1() + " and " + sharedResource.getSharedPar2());
sharedResource.setSharedPar1(sharedResource.getSharedPar1() + 1);
sharedResource.setSharedPar2(sharedResource.getSharedPar2() + "a");
}
System.out.println();
}
現在,想法是這樣 - 有兩個線程對變量sharedPar1和sharedPar2進行不同的操作,在 output 我想獲得變量的一致值,這意味着我希望能夠將該程序的 output 邏輯連接到它的代碼行。 但是,我不知道為什么我的 output 中有一些東西。 基本上,我需要有人向我解釋這種output:
Main thread! - Shared resources: 1000 and
Main thread! - Shared resources: 1101 and ba
Main thread! - Shared resources: 1102 and baa
Main thread! - Shared resources: 1103 and baaa
Main thread! - Shared resources: 1104 and baaaa
Main thread! - Shared resources: 1105 and baaaaa
Main thread! - Shared resources: 1106 and baaaaaa
Main thread! - Shared resources: 1107 and baaaaaaa
Main thread! - Shared resources: 1108 and baaaaaaaa
Main thread! - Shared resources: 1109 and baaaaaaaaa
Task2, it. 0. - Shared resources: 1100 and b
Task1, it. 0. - Shared resources: 1100 and b
Task2, it. 1. - Shared resources: 1210 and baaaaaaaaaab
Task1, it. 1. - Shared resources: 2210 and baaaaaaaaaabc
Task1, it. 2. - Shared resources: 3310 and baaaaaaaaaabcc
Task2, it. 2. - Shared resources: 3310 and baaaaaaaaaabcb
Task1, it. 3. - Shared resources: 4310 and baaaaaaaaaabcbc
Task2, it. 3. - Shared resources: 4410 and baaaaaaaaaabcbcb
Task1, it. 4. - Shared resources: 5410 and baaaaaaaaaabcbcbc
Task2, it. 4. - Shared resources: 5510 and baaaaaaaaaabcbcbcb
Task1, it. 5. - Shared resources: 6510 and baaaaaaaaaabcbcbcbc
Task2, it. 5. - Shared resources: 6610 and baaaaaaaaaabcbcbcbcb
Task1, it. 6. - Shared resources: 7610 and baaaaaaaaaabcbcbcbcbc
Task2, it. 6. - Shared resources: 7710 and baaaaaaaaaabcbcbcbcbcb
Task1, it. 7. - Shared resources: 8710 and baaaaaaaaaabcbcbcbcbcbc
Task1, it. 8. - Shared resources: 9810 and baaaaaaaaaabcbcbcbcbcbcc
Task1, it. 9. - Shared resources: 10810 and baaaaaaaaaabcbcbcbcbcbccc
Task2, it. 7. - Shared resources: 9810 and baaaaaaaaaabcbcbcbcbcbcb
Task2, it. 8. - Shared resources: 10910 and baaaaaaaaaabcbcbcbcbcbcccb
Task2, it. 9. - Shared resources: 11010 and baaaaaaaaaabcbcbcbcbcbcccbb
我了解 output 中的所有內容,直到Task2 行。 0. - 共享資源:1100 和 b - 為什么在這一行中我們沒有前一行的值(主循環中的最后一行)? Output 的主要部分,我們在字符串中添加了“aaa..”,而添加到 integer 變量中的那些在這一行中找不到,這就是我不明白的。
所以,基本上我希望能夠在多個不同線程之間使用共享的 class 和變量,但即使我將變量設置為“易失性”並將方法設置為“同步”,輸出到屏幕時再次無法正確更新值。 有人可以解釋這是為什么嗎? 如果你發現這是做這些事情的錯誤方式,我錯在哪里?
另外,我想知道是否有一種方法可以確保在一個線程中,我們總是執行一個循環的完整迭代,然后調度程序將我們的線程踢出處理器?
有幾個問題。 首先,您在獲取/設置周期上有一個競爭條件,以便每個線程可以讀取相同的初始值,因此它們替換另一個線程的更新值。 這是因為您沒有在整個塊上同步每個獨立變量的原子更改,並且兩個線程在每個運行sharedResource.setSharedParX(updatedValue)
) 之前執行getSharedParX()
) :
sharedResource.setSharedParX(sharedResource.getSharedParX() + x);
因此,您的讀取/更新時間線會踐踏其他線程的結果(請注意,在更新之前主要打印),並且這些線程的 output 的第一行使用sharedPar1
和sharedPar2
的第一個/第二個值的混合:
// Task1 read sharedPar1=0 and saved sharedPar1=1000
Main thread! - Shared resources: 1000 and
// Task2 reads sharedPar1=1000 and saved sharedPar1=1100 (trampling main values)
// Task2 read sharedPar2="" and saved sharedPar2="b" (trampling main/Task2 values)
Task2, it. 0. - Shared resources: 1100 and b
Task1, it. 0. - Shared resources: 1100 and b
其次注意System.out
是一個PrintWriter
所以println
消息是同步的。 在 Task1/Task2 有機會之前,主線程能夠打印更多結果,這就是為什么 Task1/2 的第一行出現在列表中的原因。 在線程內部打印到相同的 stream 通常不是一個好主意,因為 I/O 爭用可能會減慢所有線程,因為它們相互競爭以寫入 output。
您需要修復以使操作是原子的 - 查看使用AtomicInteger
或AtomicReference<String>
或實現您自己的處理程序以執行一步所需的更改(並刪除 setX),例如:
synchronized int addAndGet(int delta) {
sharedPar1 += delta;
return sharedPar1;
}
synchronized String appendAndGet(String delta) {
sharedPar2 += delta;
return sharedPar2;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.