同時プログラミング練気期(一)【基礎】


れんきじかん


練習期間1階(this)


synchronized(this)メソッドとsynchronizedメソッドは、現在のオブジェクトをロックします.
public class Test_01 {
	private int count = 0;  //  
	private Object o = new Object();    //  

	//  , 
	public void testSync1() {
		synchronized (o) {
			System.out.println(Thread.currentThread().getName()
					+ " count = " + count++);
		}
	}

	public void testSync2() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName()
					+ " count = " + count++);
		}
	}

	public synchronized void testSync3() {
		System.out.println(Thread.currentThread().getName()
				+ " count = " + count++);
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		final Test_01 t = new Test_01();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.testSync3();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.testSync3();
			}
		}).start();
	}

}


れんき期二層


現在のタイプのクラスオブジェクトをロックする静的同期方法.
public class Test_02 {
	private static int staticCount = 0;
	
	public static synchronized void testSync4(){
		System.out.println(Thread.currentThread().getName() 
				+ " staticCount = " + staticCount++);
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void testSync5(){
		synchronized(Test_02.class){
			System.out.println(Thread.currentThread().getName() 
					+ " staticCount = " + staticCount++);
		}
	}
	
}

れんき期三層


ロックの目的は操作の原子性を保証することである.
public class Test_03 implements Runnable {

	private int count = 0;

	@Override
	public /*synchronized*/ void run() {
		System.out.println(Thread.currentThread().getName()
				+ " count = " + count++);
	}

	public static void main(String[] args) {
		Test_03 t = new Test_03();
		for (int i = 0; i < 5; i++) {
			new Thread(t, "Thread - " + i).start();
		}
	}

}

れんき期四層


同期メソッドは、同じロックオブジェクトをロックする同期メソッドにのみ影響します.他のスレッドが非同期メソッドを呼び出すか、他のロックリソースを呼び出す同期メソッドには影響しません.
public class Test_04 {
	Object o = new Object();

	public synchronized void m1() { //  。
		System.out.println("public synchronized void m1() start");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("public synchronized void m1() end");
	}

	public void m3() {
		synchronized (o) {
			System.out.println("public void m3() start");
			try {
				Thread.sleep(1500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("public void m3() end");
		}
	}

	public void m2() {
		System.out.println("public void m2() start");
		try {
			Thread.sleep(1500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("public void m2() end");
	}

	public static class MyThread01 implements Runnable {
		public MyThread01(int i, Test_04 t) {
			this.i = i;
			this.t = t;
		}

		int i;
		Test_04 t;

		public void run() {
			if (i == 0) {
				t.m1();
			} else if (i > 0) {
				t.m2();
			} else {
				t.m3();
			}
		}
	}

	public static void main(String[] args) {
		Test_04 t = new Test_04();
		new Thread(new Test_04.MyThread01(0, t)).start();
		new Thread(new Test_04.MyThread01(1, t)).start();
		new Thread(new Test_04.MyThread01(-1, t)).start();
	}

}

れんき期五層


同期メソッドは、現在のメソッドの原子性のみを保証し、複数のビジネス・メソッド間の相互アクセスの原子性を保証することはできません.一般的に、ビジネスプロジェクトでは、ビジネスロジック上の汚い読み取り問題は考慮されません.もしあなたが買い物をして注文した後、注文がすでに下がったことを提示して、照会する時、見えないかもしれません.一般的には、データの汚れ読みだけに注目します.しかし、金融分野では保険分野が厳しく要求されている.
public class Test_05 {
	private double d = 0.0;
	public synchronized void m1(double d){
		try {
			//  。
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.d = d;
	}
	
	public double m2(){
		return this.d;
	}
	
	public static void main(String[] args) {
		final Test_05 t = new Test_05();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m1(100);
			}
		}).start();
		System.out.println(t.m2());
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t.m2());
	}
	
}

れんき期六層


同じスレッドで、同期コードを複数回呼び出し、同じロックオブジェクトをロックし、再読み込みできます.
public class Test_06 {
	
	synchronized void m1(){ //  this
		System.out.println("m1 start");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		m2();
		System.out.println("m1 end");
	}
	synchronized void m2(){ //  this
		System.out.println("m2 start");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m2 end");
	}
	
	public static void main(String[] args) {
		
		new Test_06().m1();
		
	}
	
}

練気期7層(親を呼び出す同期方法)


サブクラス同期メソッドは、親の同期メソッドを上書きし、ロックの再読み込みに相当する親を呼び出す同期メソッドを指定できます.親のメソッド<=>>このクラスのメソッド
public class Test_07 {

	synchronized void m() {
		System.out.println("Super Class m start");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Super Class m end");
	}

	public static void main(String[] args) {
		new Sub_Test_07().m();
	}

}

class Sub_Test_07 extends Test_07 {
	synchronized void m() {
		System.out.println("Sub Class m start");
		super.m();
		System.out.println("Sub Class m end");
	}
}

練気期8層(ロックと異常)


同期メソッドで異常が発生した場合、ロックリソースが自動的に解放され、他のスレッドの実行に影響しません.同期ビジネスロジックで異常が発生した場合、try/catchをどのように処理するかに注意してください.お金を貯める時、ネットを送って中断して、調べる時いくらまで調べて、貯金したお金は返します
public class Test_08 {
	int i = 0;

	synchronized void m() {
		System.out.println(Thread.currentThread().getName() + " - start");
		while (true) {
			i++;
			System.out.println(Thread.currentThread().getName() + " - " + i);
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			/*if(i == 5){
				i = 1/0;
			}*/
			// , 
			if (i == 5) {
				try {
					i = 1 / 0;
				} catch (Exception e) {
					i = 0;
				}
			}
		}
	}

	public static void main(String[] args) {
		final Test_08 t = new Test_08();
		//  
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m();
			}
		}, "t1").start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m();
			}
		}, "t2").start();
	}

}

練気期九層(volatile)


cpuはデフォルトでcpuのキャッシュ領域をクエリーし、CPUの各コアには独自のキャッシュがあり、cpuが中断した場合、キャッシュ領域のデータを空にし、メモリからデータを再読み込みする可能性があります.volatileはメモリ中のデータを変更し、下位OSシステムに通知し、bを使用するたびにメモリデータが変動しているかどうかを見たほうがいい.つまりvolatileはOSシステムに通知する作品です.
public class Test_09 {
	
	volatile boolean b = true;	// 
	
	void m(){
		System.out.println("start");
		while(b){}
		System.out.println("end");
	}
	
	public static void main(String[] args) {
		final Test_09 t = new Test_09();
		new Thread(new Runnable() {
			@Override
			public void run() {
				t.m();
			}
		}).start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		t.b = false;	// , 
	}
	
}

volatileの非原子性問題は,可視性のみを保証し,原子性を保証することはできない.
volatileはいつ使いますか?将棋室の人数は、新たに追加された人が+1のスレッドを持っています.これはvolatileが使えます
join()複数のスレッドが実行終了すると、複数のスレッドの再mainスレッドの位置を接続し、他のスレッドが終了すると、すべてのスレッドが+1サイクル実行された後、mainスレッド印刷が実行されることを保証します.
public class Test_10 {

	volatile int count = 0;

	/*synchronized*/ void m() {    // synchronized Atomic
		for (int i = 0; i < 10000; i++) {
			count++;
		}
	}

	public static void main(String[] args) {
		final Test_10 t = new Test_10();
		List<Thread> threads = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			threads.add(new Thread(new Runnable() {
				@Override
				public void run() {
					t.m();
				}
			}));
		}
		for (Thread thread : threads) {
			thread.start();
		}
		for (Thread thread : threads) {
			try {
				thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(t.count);    // 10w。 
	}
}

練気期十層(AtomicXxx)


いつ原子性があって、可視性がありませんか?
*A:原子性とは、複数のスレッドが1つの変数にアクセスする場合、その結果が正確であることを保証しなければならないことを意味します.*可視性とは,マルチスレッド間で最終結果が見られる変数である.
public class Test_11 {
    AtomicInteger count = new AtomicInteger(0);

    void m() {
        for (int i = 0; i < 10000; i++) {
            /*if(count.get() < 1000)*/
            count.incrementAndGet();    // ++count,count.getAndAccumulate() count++;
        }
    }

    public static void main(String[] args) {
        final Test_11 t = new Test_11();
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    t.m();
                }
            }));
        }
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println(t.count.intValue());
    }
}

エアトレーニング期間11階(ロック対象変更)

  • 同期コードがロックされると、一時的なロック参照がロックオブジェクトを指し、実際の参照と直接関連付けられません.ロックが解放されない前に、ロック参照を変更しても、同期コードの実行には影響しません.
  • 印刷したのはTestです13のo.ロック参照ではありません_O;次のsynchronizedロックは2つのオブジェクトです.同じオブジェクトを印刷します.
  • public class Test_13 {
    	Object o = new Object();    // 
    
    	int i = 0;
    
    	int a() {
    		try {
    			/*
    			 * return i ->
    			 * int _returnValue = i; // 0;
    			 * return _returnValue;
    			 */
    			return i;
    		} finally {
    			i = 10;
    		}
    	}
    
    	void m() {
    		System.out.println(Thread.currentThread().getName() + " start");
    		synchronized (o) {    // 
    			while (true) {
    				try {
    					TimeUnit.SECONDS.sleep(1);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				System.out.println(Thread.currentThread().getName() + " - " + o);
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		final Test_13 t = new Test_13();
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				t.m();
    			}
    		}, "thread1").start();
    		try {
    			TimeUnit.SECONDS.sleep(3);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		Thread thread2 = new Thread(new Runnable() {
    			@Override
    			public void run() {
    				t.m();
    			}
    		}, "thread2");
    		t.o = new Object();
    		thread2.start();    // 
    
    		System.out.println(t.i);
    		System.out.println(t.a());
    		System.out.println(t.i);
    	}
    
    }
    

    練気期12層(CountDownLatch)

  • は待機キューには入らず、ロックと混合して使用したり、ロックの機能を代替したりすることができます.
  • は一度にドアに複数のロックを掛けます.
  • は、initオブジェクトの場合、前後の順序の問題があります.
  • public class Test_15 {
        CountDownLatch latch = new CountDownLatch(5);
    
        void m1() {
            try {
                latch.await();//  。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("m1() method");
        }
    
        void m2() {
            for (int i = 0; i < 10; i++) {
                if (latch.getCount() != 0) {
                    System.out.println("latch count : " + latch.getCount());
                    latch.countDown(); //  。
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("m2() method : " + i);
            }
        }
    
        public static void main(String[] args) {
            final Test_15 t = new Test_15();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t.m1();
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t.m2();
                }
            }).start();
        }
    
    }
    
    

    訓練期間が大いに円満である.

    public class Test_14 {
        String s1 = "hello";
        String s2 = new String("hello"); // new , 。
        Integer i1 = 1;    // i1 i2 , ,new 
        Integer i2 = 1;
    
        void m1() {
            synchronized (i1) {    //s1 s2
                System.out.println("m1()");
                while (true) {
    
                }
            }
        }
    
        void m2() {
            synchronized (i2) {
                System.out.println("m2()");
                while (true) {
    
                }
            }
        }
    
        public static void main(String[] args) {
            final Test_14 t = new Test_14();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t.m1();
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t.m2();
                }
            }).start();
        }
    
    }
    
    

    コンテナをカスタマイズし、新しい要素(add)と要素数(size)の取得方法を提供します.2つのスレッドを開始します.スレッド1はコンテナに10個のデータを追加します.スレッド2は、コンテナ要素の数をリスニングし、コンテナ要素の数が5の場合、スレッド2は情報を出力して終了する.
  • volatile
  • を使用
    public class Test_01 {
    	public static void main(String[] args) {
    		final Test_01_Container t = new Test_01_Container();
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				for (int i = 0; i < 10; i++) {
    					System.out.println("add Object to Container " + i);
    					t.add(new Object());
    					try {
    						TimeUnit.SECONDS.sleep(1);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}).start();
    
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				while (true) {
    					if (t.size() == 5) {
    						System.out.println("size = 5");
    						break;
    					}
    				}
    			}
    		}).start();
    	}
    }
    
    class Test_01_Container {
    	volatile List<Object> container = new ArrayList<>();
    
    	public void add(Object o) {
    		this.container.add(o);
    	}
    
    	public int size() {
    		return this.container.size();
    	}
    }
    
  • synchronizedおよびwait()を使用してwait()を呼び出すとロックが解放され、生産者および消費者モデル
  • が待機キューに入る.
    public class Test_02 {
    	public static void main(String[] args) {
    		final Test_02_Container t = new Test_02_Container();
    		final Object lock = new Object();
    		
    		new Thread(new Runnable(){
    			@Override
    			public void run() {
    				synchronized (lock) {
    					if(t.size() != 5){
    						try {
    							lock.wait(); //  。
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    					System.out.println("size = 5");
    					lock.notifyAll(); //  
    				}
    			}
    		}).start();
    		
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				synchronized (lock) {
    					for(int i = 0; i < 10; i++){
    						System.out.println("add Object to Container " + i);
    						t.add(new Object());
    						if(t.size() == 5){
    							lock.notifyAll();
    							try {
    								lock.wait();
    							} catch (InterruptedException e) {
    								e.printStackTrace();
    							}
    						}
    						try {
    							TimeUnit.SECONDS.sleep(1);
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    				}
    			}
    		}).start();
    	}
    }
    
    class Test_02_Container{
    	List<Object> container = new ArrayList<>();
    	
    	public void add(Object o){
    		this.container.add(o);
    	}
    	
    	public int size(){
    		return this.container.size();
    	}
    }
    
  • は、ラッチを使用して待機キューに入ることを回避し、より効率的です.
  • public class Test_03 {
    	public static void main(String[] args) {
    		final Test_03_Container t = new Test_03_Container();
    		final CountDownLatch latch = new CountDownLatch(1);
    
    		new Thread(new Runnable(){
    			@Override
    			public void run() {
    				if(t.size() != 5){
    					try {
    						latch.await(); //  。  
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				System.out.println("size = 5");
    			}
    		}).start();
    		
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				for(int i = 0; i < 10; i++){
    					System.out.println("add Object to Container " + i);
    					t.add(new Object());
    					if(t.size() == 5){
    						latch.countDown(); //  -1
    					}
    					try {
    						TimeUnit.SECONDS.sleep(1);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}).start();
    	}
    }
    
    class Test_03_Container{
    	List<Object> container = new ArrayList<>();
    	
    	public void add(Object o){
    		this.container.add(o);
    	}
    	
    	public int size(){
    		return this.container.size();
    	}
    }