1. 程式人生 > >如何解決執行緒安全問題

如何解決執行緒安全問題


有2種解決方法。
第一,是採用原子變數,畢竟執行緒安全問題最根本上是由於全域性變數和靜態變數引起的,只要保證了對於變數的寫操作要麼全寫要麼不寫,就可以解決執行緒安全,定義變數用sig_atomic_t和volatile。
第二,就是實現執行緒間同步啦,用互斥索,訊號量。讓執行緒有序的訪問變數就可以啦
在編寫一個類時,如果該類中的程式碼可能運行於多執行緒環境下,那麼就要考慮同步的問題,Java實現執行緒同步的方法很多,具體如下。
(1)synchronized關鍵字
     
在Java中內建了語言級的同步原語synchronized關鍵字,其在多執行緒條件下實現了對共享資源的同步訪問。根據synchronized關鍵字修飾的物件不同可以分為以下幾種情況。
      
*synchronized關鍵字同步方法
           
public synchronized void 
method(){
                
//do 
something
            
}
          
注意:如果使用synchronized關鍵字同步方法,很容易誤認為同步關鍵字鎖住了它所包圍的程式碼。但是實際情況卻不是這樣,同步加鎖的是物件而並非程式碼。因此。如果在一個類中有一個同步方法,該方法是可以被兩個不同的執行緒同時執行的,只要每個執行緒自己建立一個該類的例項即可。
           
示例程式碼:
package newthread;

public class TestSync {
    
public static void main(String[] args) {
    
    MyThread1 my1=new MyThread1(1);
    
    MyThread1 my2=new MyThread1(3);
    
    my1.start();
        
my2.start();
    }
}
class MyThread1 extends 
Thread{
    private int val;
    public 
MyThread1(int v){
        
val=v;
    }
    public synchronized void 
printVal(int v){
        for(int 
i=0;i<100;i++){
            
System.out.print(v);
        
}
    }
    public void 
run(){
        
printVal(val);
    }
}
    
執行程式碼結果是1和3交叉輸出的,即1和3兩個執行緒在併發執行printVal方法,並沒有實現同步功能。原因在於synchronized關鍵字鎖定的是物件而並非程式碼塊,如果需要實現真正的同步,必須同步一個全域性物件或者對類進行同步。synchronized關鍵字同步類的格式如下:
synchronized(MyThread.class){}
改進程式碼
package 
newthread;

public class TestSync_2 {
    public static 
void main(String[] args) {
        MyThread_2 
my1=new MyThread_2(1);
        
my1.start();
        MyThread_2 my2=new 
MyThread_2(2);
        
my2.start();
    }
}
    class MyThread_2 
extends Thread{
        private int 
val;
        public MyThread_2(int 
v){
            
val=v;
        }
    
    public void printVal(int v){
    
        
synchronized(MyThread_2.class){
        
        for(int 
i=0;i<100;i++){
            
        System.out.print(v);