[英]Is this okay to do with threads and blocking queues?
我想知道是否可以讓線程訪問類的實例,以便您可以對該類的某些成員/變量執行操作。
例如,我同時擁有一個主線程和一個線程。 我給第二個線程訪問主類的實例,以便可以在x上執行操作。
但是,如果將來某個時候我決定對主線程中的x進行操作怎么辦? 或者只是從x中讀取。 如果另一個線程和主線程都想同時讀取x怎么辦?
通過在代碼中進行結構化的方式,這完全可以嗎?
package test;
import java.lang.Thread;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class AThread extends Thread {
Test test;
AThread(Test test) {
this.test = test;
}
BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
public void run() {
String msg;
while ((msg = queue.poll()) != null) {
// Process the message
//System.out.println(msg); //should print "hello"
if (msg.equals("up")) {
test.setX(test.getX()+1);
System.out.println(test.getX());
}
}
}
}
public class Test {
AThread aThread;
private int x = 5;
void setX(int x){
this.x = x;
}
int getX(){
return x;
}
Test() throws InterruptedException{
System.out.println("MainThread");
aThread = new AThread(this);
aThread.start();
while (true) {
aThread.queue.put("up");
}
}
public static void main(String[] args) throws InterruptedException {
new Test();
}
}
不僅是成員“ x”,而且在“測試”類中可能還希望有更多的成員能夠執行讀/寫等操作。
這樣行嗎? 如果沒有,應該解決什么問題?
您的代碼有幾個問題。
考慮這一行:
aThread = new AThread(this);
它始終是一個壞主意,通過this
地方在構造函數中。 這與線程無關...。 其原因是,“地方”可以調用一個方法在this
,該方法可以在子類中它的構造當時尚未被稱作被覆蓋,也可能在災難結束了,因為這可能會覆蓋使用某些子類的字段是還沒有初始化。
現在,當線程進入畫面時,情況變得更糟。 保證線程可以正確訪問在線程啟動之前創建的類實例。 但是在您的情況下,它尚未創建,因為構造函數尚未完成! 由於下面的無限循環,它不可能很快完成:
while (true) {
aThread.queue.put("up");
}
因此,您具有與線程啟動並行運行的對象創建。 Java不保證在這種情況下該線程將看到初始化的類(即使沒有循環)。
這也是為什么在構造函數中啟動線程被認為是一個壞主意的原因之一。 在這種情況下,某些IDE甚至會發出警告。 注意,在構造函數中運行無限循環可能也是一個壞主意。
如果將代碼移到run()
方法中,並在main()
執行new Test().run()
main()
,則代碼看起來會很好,但是您可以擔心
但是,如果將來某個時候我決定對主線程中的x進行操作怎么辦?
最好的主意是讓主線程在將對象傳遞給線程之后就忘記該對象:
public static void main(String[] args) throws InterruptedException {
AThread aThread = new AThread(new Test());
aThread.start();
while (true) {
aThread.queue.put("up");
}
}
但是,如果將來某個時候我決定對主線程中的x進行操作怎么辦? 或者只是從x中讀取。 如果另一個線程和主線程都想同時讀取x怎么辦?
每當您在兩個線程之間共享信息時,都需要提供內存同步。 在這種情況下,如果將int x
為volatile int x
則您的代碼應該可以正常工作。 您應該閱讀有關該主題的Java教程 。
但是,如果線程正在執行更復雜的操作,而不是僅設置或獲取x
,那么您可能需要使方法synchronized
或以其他方式提供互斥鎖,以確保兩個線程不會不正確地重疊。
例如,如果您需要增加x
的值,則volatile
將無濟於事,因為增量實際上是3個操作:獲取,增量和設置。 您可以使用synchronized
鎖來保護++,或者應該考慮使用AtomicInteger
,該AtomicInteger
以線程安全的方式處理incrementAndGet()
AtomicInteger
incrementAndGet()
方法。
@Segey的答案為您的其余代碼提供了很好的反饋。 我將對此代碼添加一條評論:
while (true) {
aThread.queue.put("up");
}
您幾乎永遠都不想這樣旋轉。 如果您想做這樣的事情,那么我將添加一些Thread.sleep(10)
或一些減慢隊列添加速度或使隊列的大小受限的東西。 您可能會耗盡內存,無法像這樣創建隊列元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.