JAvaスレッドセキュリティsynchronized同期ブロックと同期方法の応用

3917 ワード

package study_02;

public class unsafeThread{
	public static void main(String[] args) {
		Web12306 web12306 = new Web12306();
		new Thread(web12306,"  A").start();
		new Thread(web12306,"  B").start();
		new Thread(web12306,"  C").start();
		
	}
}


class Web12306 implements Runnable{
	private int ticketNum = 10;
	private boolean flag = true;
	@Override
	public void run() {
		test();
	}
	public void  test() {
		while (flag) {
			if (ticketNum <= 0) {
				flag = false;
				break;
			}else {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "----->"+ ticketNum--);
			}
		}
	}
}

実行後に検出されます
  C----->9
  A----->9
  B----->10
  A----->8
  C----->8
  B----->7
  A----->6
  B----->5
  C----->6
  A----->4
  C----->3
  B----->4
  A----->2
  C----->2
  B----->2
  C----->1
  A----->-1
  B----->0

2つの9が表示されます スレッドが安全でない場合-1も発生します
2つの9が出現したのは、各スレッドに独自のワークスペースがあるためであり、彼らはすべてホストと付き合い、ホストのticketNum=10、各スレッドはticketNum=10をそれぞれのワークスペースにコピーし、スレッドAがticketNumを10に取得した後、自分のワークスペースにコピーし、IO操作を行い、これがticketNumなのか10なのか、スレッドCがCPUに呼び出され、また、tickNumを10にコピーして自分のスペースにコピーすると、Aが呼び出され、tickNumの数値を修正してticketNUmを1から9に変更し、スレッドCの後も呼び出す、tickNumを1から9に変更する.
-1が現れるのは、チケットが1枚ある場合、スレッドCが呼び出されてもう1枚のチケットが見え、ticketNum=1を取得し、10 msのIO操作が行われるためである.このときticketNumはまだ修正されていないのか1なのか、このときスレッドBがIO操作を行っている場合、スレッドBも残りのチケットが1つあるのを見て、再びIO操作に入る.そしてスレッドBはticketNumに対して1つ減算ように呼び出され、同様のスレッドAである、最後に表示されるスレッドCは1スレッドBが0、スレッドAは-1である.
同期ロックをかける
package study_3;
/*
 *         
 * 
 * 
 * 
 */
public class synTest2{
	public static void main(String[] args) {
		synWeb12306 web12306 = new synWeb12306();
		new Thread(web12306,"  A").start();
		new Thread(web12306,"  B").start();
		new Thread(web12306,"  C").start();
		
	}
}


class synWeb12306 implements Runnable{
	private int ticketNum = 10;
	private boolean flag = true;
	@Override
	public void run() {
		test();
	}
	public synchronized void test() {//                   
		while (flag) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			if (ticketNum <= 0) {
				flag = false;
				break;
			}else {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "------>" +ticketNum--);
			}
		}
	}
}
  A------>10
  A------>9
  A------>8
  A------>7
  A------>6
  A------>5
  A------>4
  A------>3
  A------>2
  A------>1

例2
package study_02;

import java.util.ArrayList;
import java.util.List;

public class unsafeThread4 {
	public static void main(String[] args) throws InterruptedException {
		List list = new ArrayList();
		for (int i = 0; i < 10000; i++) {
			new Thread(()->{
				list.add(Thread.currentThread().getName());
			}).start();
		}
		Thread.sleep(1000);//list      
		System.out.println(list.size());
	}
}

結果は9998で、本来は10000であるべきです.これは同期ロック、同期ブロックです.
package study_02;

import java.util.ArrayList;
import java.util.List;

public class unsafeThread4 {
	public static void main(String[] args) throws InterruptedException {
		List list = new ArrayList();
		for (int i = 0; i < 10000; i++) {
			new Thread(()->{
				synchronized (list) {//   
					list.add(Thread.currentThread().getName());
				}
			}).start();
		}
		Thread.sleep(1000);//list      
		System.out.println(list.size());
	}
}