对于下面的程序:
public class MyThread extends Thread{
private Object obj;
......
}
请问,这个MyThread里面的成员变量,是不是线程安全的?
因为,MyThread继承了Thread,其使用方式为:new MyThread().start();
所以,这就意味着,每次都是new了新对象,那么,他里面的各个成员变量就是这个对象自己拥有的,所以,是安全的。
我这样理解有问题吗?
PHPz2017-04-18 10:51:12
線程安全與否和是否在多個線程中使用有關
雖然你定義的是private
,但有很多種方法都可以在其它線程中間接的訪問到它,所以它存在在多個線程中使用的可能,但是代碼裡又沒有加入同步處理,所以它是不安全的。
使用 Thread 和 Runnable 並沒有什麼不同:
public class Test {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
// MyRunable mr = new MyRunable();
// new Thread(mr).start();
// new Thread(mr).start();
// new Thread(mr).start();
}
}
class MyThread extends Thread {
private int ticket = 10;
public void run() {
for (int i = 0; i < 20; i++) {
if (this.ticket > 0) {
System.out.println("thread: " + this.ticket--);
}
}
}
}
class MyRunable implements Runnable {
private int ticket = 10;
public void run() {
for (int i = 0; i < 20; i++) {
if (this.ticket > 0) {
System.out.println("runable: " + this.ticket--);
}
}
}
}
一個不案例的運行範例(要多運行幾次才遇得到)
thread: 10
thread: 9
thread: 7
thread: 10
thread: 6
thread: 8
thread: 3
thread: 4
thread: 5
thread: 1
thread: 2
ringa_lee2017-04-18 10:51:12
每次都是new了新對象,那麼,他裡面的這個map就是這個對象自己擁有的,所以,是安全的。
這句話是沒錯的,除非你在調用子線程的這個主線程中聲明了公共成員(變量)並且在子線程內部操作了這個公共變量,或者你把這個公共變量按引用傳遞進了子線程內部並且在子線程內部操作了它,這樣才會導致線程不安全問題的出現,至於map類型本身是不是線程安全我也忘了(我記得map是一個接口,是否為線程安全要看他的具體實現把),你百度一下把。 。 。
如果map的實作本身就是線程安全,那麼無論你在多執行緒內部怎麼操作都是沒事的。 (即使他在主線程中聲明並且按引用傳入了子線程中)
具體線程安全科普知識可以看看我以前寫過的文章https://zhuanlan.zhihu.com/p/...
PHPz2017-04-18 10:51:12
怎麼說呢,這就好比:
你把錢裝在了手提箱裡,一個人走在街上。
你覺得這是安全的,當然了。
但是一旦被搶,就不安全了。 。 。
線程安全說的是不同線程訪問同一個數據,如果只存在一個線程,就談不上什麼線程安不安全。或者你也可以理解為是“安全”的,畢竟沒有其他對象來訪問,但是不是“線程安全”
回答一下問題:
這個map對象,是線程不安全的嗎?
是的,線程不安全。
因為雖然這裡每個Thread對像都擁有唯一獨立的Map對象,但卻沒有「線程安全的能力」。
嘛,我的理解就是這樣的,好像有點囉嗦了。 。 。 ==
迷茫2017-04-18 10:51:12
雖然你宣告的private但還是可以在另一個執行緒裡讀取該變量,在沒有加同步鎖的情況下就是執行緒不安全的。
题主想的这种线程安全的变量应该是在run方法里面声明的,这样的话对象就存在于线程工作内存里独享。
伊谢尔伦2017-04-18 10:51:12
在多執行緒的情況下
public class MyThread extends Thread{
private Object obj;
public void run(){
if(obj==null){//A位置,这个地方是关键
obj = new Object();
system.out.println("null");
}
}
}
MyThread thread = new MyThread();
//假设我的系统CPU是4核,那么实际上系统可以同时并行跑4个线程,这个时候我是同一个对象,
//假设我第一个跑到A的位置,第二个也刚好跑到这个位置,
//那当我第一个跑完obj是==null走到下一步的时候,obj已经重新new一个对象,
//这个时候obj!=null,这可能导致的结果就是有部分无法走进A代码块里面去,
//实际上在程序设计上应该需要让他走到A代码里面去的,这样就导致了线程安全的问题。
thread.start();
thread.start();
thread.start();
thread.start();