スレッドが安全でない理由


package ThreadTest;

public class ThreadTest {
	public static void main(String args[]){
        MyThread mt = new MyThread() ;    //  
   
        Thread t1 = new Thread(mt) ;    //  Thread 
        Thread t2 = new Thread(mt) ;    //  Thread 
        Thread t3 = new Thread(mt) ;    //  Thread 
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

class MyThread implements Runnable{
    private int ticket = 5 ;    //  5 
    public void run(){
//        synchronized (this){
        while(ticket>0){
       
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(" :ticket = " + ticket-- );
            }
//        }
    }
}

 
 
 
スレッド不安全条件
 
1 mtはオブジェクトインスタンスです
2複数のスレッドが同時に1つのオブジェクトインスタンスの属性を変更し、各スレッドにはオブジェクトインスタンスの値を保存するための独自の一時的なスペースがあるため、この値は変更後すぐにオブジェクトに同期することはなく、他のスレッドがオブジェクトインスタンスの最新の値ではなく、データの汚れ、書き込みをもたらす
 
実行結果は次のとおりです.
 
 
チケット販売:チケット=5
チケット販売:チケット=5
チケット販売:チケット=4
チケット販売:チケット=3
チケット販売:チケット=2
チケット販売:チケット=3
チケット販売:チケット=1
チケット販売:チケット=0
チケット:ticket=-1
 
 
 
修正:コードブロックを同期し、1時間で1つのスレッドだけがコードにアクセスできるようにします.データの変更が単一スレッドで同期されることを保証します
 
 
class MyThread implements Runnable{
    private int ticket = 5 ;    //  5 
    public void run(){
        synchronized (this){
        while(ticket>0){
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(" :ticket = " + ticket-- );
            }
        }
    }
}


 :ticket = 5
 :ticket = 4
 :ticket = 3
 :ticket = 2
 :ticket = 1
 
        synchronized (this){
}
同期はコードセグメントではなく属性です(thisはクラスを表します.つまり、このクラスの他の方法も同期されますか?)
 
 
改善用byte[]lock={0};代わりに省メモリの比較
 
class MyThread implements Runnable{
    private int ticket = 5 ;    //  5 
    private byte[] lock = {0};
    public void run(){
        synchronized (lock){
        while(ticket>0){
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(" :ticket = " + ticket-- );
            }
        }
    }
}

 
または直接synchronizedマルチスレッドアクセス変更されたプロパティsynchronizedの配列
 
class MyThread implements Runnable{
    private int[] ticket = {5} ;    //  5 
    public void run(){
    	synchronized(ticket){
    		sale();	
    	}
    }
    private void sale(){
    	 while(ticket[0]>0){
             try {
                 Thread.sleep(300);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             System.out.println(" :ticket = " + ticket[0]-- );
         }
    }
}
 
 
2同期方法
 
 
 
class MyThread implements Runnable{
    private  int ticket = 5 ;    //  5 
    public void run(){
    	sale();
    }
    private synchronized void sale(){
    	 while(ticket>0){
             try {
                 Thread.sleep(300);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             System.out.println(" :ticket = " + ticket-- );
         }
    }
}
 
 
 
 
 
 
 
 
以下はスレッドが安全ですが、Threadクラスを継承すると、リソース(ticket)は共有されず、それぞれのチケットを販売します.runnableインタフェースの実装はリソース共有可能である
 
package ThreadTest;

public class ThreadTestFirst {
	public static void main(String args[]){
		MyThreadF a = new MyThreadF("a");
		MyThreadF b = new MyThreadF("b");
		a.start();
		b.start();
    }
}

class MyThreadF extends Thread{
    private int ticket = 5 ;    //  5 
    private String name;
    public MyThreadF(String name) {
		this.name = name;
	}
    public void run(){
        while(ticket>0){
       
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(this.name  + " :ticket = " + ticket-- );
            }
    }
}

 
 
a :ticket = 5
b :ticket = 5
b :ticket = 4
a :ticket = 4
b :ticket = 3
a :ticket = 3
b :ticket = 2
a :ticket = 2
a :ticket = 1
b :ticket = 1