JAvaマルチスレッド(二)--複数のスレッドが共有オブジェクトとデータにアクセスする方法


スレッドに関する概念:
  • マルチスレッド:1つのプログラム(プロセス)で実行時に1つ以上のスレッドが生成されることを意味します.
  • 並列:複数のcpuインスタンスまたは複数のマシンが同時に論理処理を行い、同時に実行することを指す.
  • 同時:cpuスケジューリングアルゴリズムにより、ユーザーが同時に実行しているように見えますが、実際にはcpu操作の面から真の同時ではありません.同時は往々にしてシーンの中で公共の資源があって、それではこの資源の呼び出しに対して1つのボトルネックを生んで、私達はTPSあるいはQPSでこのシステムの処理能力に反応します.(TPS/QPS:1秒あたりのRequest/トランザクションの数).
  • スレッドセキュリティ:論理処理のコードを記述するためによく使用されます.同時の場合、このコードはマルチスレッドで使用され、スレッドの呼び出し順序は結果に影響しません.トランザクションを追加しない振り替えロジック.
  • スレッド同期:共有リソースのマルチスレッドアクセスがスレッドの安全になることを保証し、結果の正確な行を保証する.複数のスレッド呼び出しの方法にsynchronizationキーワード処理を加えると、結果を保証しながらパフォーマンスを向上させるのが優れたプログラムです.プログラムスレッドセキュリティとプログラムパフォーマンスの優先度では、スレッドセキュリティが大きくなります.

  •  
    一、各スレッドの実行コードが同じ場合、同じRunnableオブジェクトを使用することができ、このRunnableオブジェクトにはその共有データがある.
    例:切符を売る.
    public class ThreadShareBuyTicketDemo {
    	public static void main(String[] args) {
    		BuyTicket buyTicket = new BuyTicket();
    		new Thread(buyTicket," ").start();
    		new Thread(buyTicket," ").start();
    	}
    }
    class BuyTicket implements Runnable{
    	private int count = 100;
    
    	@Override
    	public void run() {
    		while(true){
    			synchronized (this) {
    				if(count > 0 ){
    					try {
    						Thread.sleep(100);
    						count--;
    						System.out.println(Thread.currentThread().getName()+" :"+count);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}else{
    				}
    			}
    		}
    	};
    	
    }
    // 
    public class SalTickets {
    	public static void main(String[] args) {
    		/**
    		 *  , Runnable , Runnable 
    		 */
    		Tickets tickets = new Tickets();
    		new Thread(tickets," ").start();
    		new Thread(tickets," ").start();
    	}
    }
    
    class Tickets implements Runnable{
    	Lock lock = new ReentrantLock();
    	private int tickeCount = 100;
    	
    	@Override
    	public void run() {
    		while(true){
    			sals();
    		}
    	}
    	public void sals(){
    		lock.lock();
    		try {
    			Thread.sleep(100);
    			if(tickeCount > 0){
    				tickeCount --;
    				System.out.println(" "+Thread.currentThread().getName()+" :"+ tickeCount );
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}finally{
    			lock.unlock();
    		}
    	}
    }

    二、各スレッドの実行コードが異なる場合、異なるRunnableオブジェクト(対線をRunnableに渡す)が必要です.
    例1:2つのスレッドがj+1ずつ、他の2つのスレッドがj−1ずつ設計される.
    public class ThreadMultiShareDemo {
    	
    	public static void main(String[] args) {
    		final ThreadMulti threadMulti = new ThreadMulti();
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				for(int i=0;i<100;i++){
    						threadMulti.increment();
    				}
    			}
    		}).start();
    		
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				for(int i=0;i<100;i++){
    						threadMulti.decrement();
    					}
    			}
    		}).start();
    	}
    	
    }
    class ThreadMulti{
    	private int j=10;
    	
    	public synchronized void increment(){
    		j++;
    		System.out.println("j++  :"+j);
    	}
    	
    	public synchronized  void decrement(){
    		j--;
    		System.out.println("j--  :"+j);
    	}
    }

    注意:ここでincrementメソッドとdecrementメソッドにsynchronizedキーを付けるのは、2つのスレッドが同じ変数を同時に操作する場合、簡単なj++操作でもシステムの下部で複数のマシン文で実現されるため、j++プロセスを実行するのに時間がかかるため、j++を実行するときに別のスレッドHがjを操作する可能性があります.したがって、他のスレッドHが動作する可能性があるのは、最新の値ではない可能性がある.したがって、スレッド同期を指定します.
    例2:消費者と生産者モデル
    生産者:消費者
    public class ProductAndCustomer {
    	public static void main(String[] args) {
    		UserAction action = new UserAction();
    		new Thread(new product(action)).start();
    		new Thread(new product(action)).start();
    	}
    	
    	static class product implements Runnable{
    		public UserAction action;
    		public product(UserAction action){
    			this.action = action;
    		}
    		
    		@Override
    		public void run() {
    			while(true){
    					action.productAction(10);
    			}
    		}
    		
    	}
    	static class customer implements Runnable{
    		public UserAction action;
    		public customer(UserAction action){
    			this.action = action;
    		}
    		
    		@Override
    		public void run() {
    			while(true){
    					action.customerAction(10);
    			}
    		}
    		
    	}
    }
    class UserAction{
    	// 
    	private int currentGoods = 0;
    	// 
    	private int maxInventory = 30;
    	// 
    	public synchronized void customerAction(int num){
    		try {
    			if(num>currentGoods){
    				System.out.println(" :"+Thread.currentThread().getName()+", , ");
    					this.wait();
    			}
    			currentGoods -= num;
    			System.out.println(" :"+Thread.currentThread().getName()+" :"+num+", :"+currentGoods);
    			this.notify();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    	// 
    	public synchronized void productAction(int num){
    		try {
    			if((num+currentGoods) > maxInventory){
    				currentGoods = 30;
    				System.out.println(" :"+Thread.currentThread().getName()+" , :"+currentGoods);
    				this.wait();
    			}
    			currentGoods += num;
    			System.out.println(" :"+Thread.currentThread().getName()+" :"+num+", :"+currentGoods);
    			this.notify();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }

    複数の生産者::複数の消費者.複数の生産者と複数の消費者がいる場合、実行結果は負の値になります.これは、スレッドが同期していないことを意味します.この場合、if判断をwhileに変更する必要があります.nitifyAll();
    理由はスレッドwait()です.スレッドが起動すると、スレッドが直接実行されるようにwhileが必要です.
    package com.XC.saleticket;
    
    public class ProductAndCustomer {
    	public static void main(String[] args) {
    		UserAction action = new UserAction();
    		new Thread(new product(action)).start();
            new Thread(new product(action)).start();
    		new Thread(new customer(action)).start();
            new Thread(new customer(action)).start();
    	}
    	
    	static class product implements Runnable{
    		public UserAction action;
    		public product(UserAction action){
    			this.action = action;
    		}
    		
    		@Override
    		public void run() {
    			while(true){
    					action.productAction(10);
    			}
    		}
    		
    	}
    	static class customer implements Runnable{
    		public UserAction action;
    		public customer(UserAction action){
    			this.action = action;
    		}
    		
    		@Override
    		public void run() {
    			while(true){
    					action.customerAction(10);
    			}
    		}
    		
    	}
    }
    class UserAction{
    	// 
    	private int currentGoods = 0;
    	// 
    	private int maxInventory = 30;
    	// 
    	public synchronized void customerAction(int num){
    		try {
    			while(num>currentGoods){
    				System.out.println(" :"+Thread.currentThread().getName()+", , ");
    					this.wait();
    			}
    			currentGoods -= num;
    			System.out.println(" :"+Thread.currentThread().getName()+" :"+num+", :"+currentGoods);
    			this.notifyAll();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    	// 
    	public synchronized void productAction(int num){
    		try {
    			while((num+currentGoods) > maxInventory){
    				currentGoods = 30;
    				System.out.println(" :"+Thread.currentThread().getName()+" , :"+currentGoods);
    				this.wait();
    			}
    			currentGoods += num;
    			System.out.println(" :"+Thread.currentThread().getName()+" :"+num+", :"+currentGoods);
    			this.notifyAll();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    まとめ:マルチスレッドではwhile文をできるだけ使用し,ロックを使用する場合lock.unlock();必ずfinallyに書いてください.this.wait();this.notify();this.notifyAll();synchronizedに書きます.
    資料:https://www.cnblogs.com/wxd0108/p/5479442.html