Thread學習之三(線程安全)

  1. 線程安全java

    1. 緣由:當多個線程訪問一個共享的資源時,會產生線程安全的問題。c++

    2. 解決方法:用synchronized關鍵字作爲多線程併發環境的執行有序性的保證手段之一。當一段代碼會修改共享變量,這一段代碼成爲互斥區或臨界區,爲了保證共享變量的正確性,synchronized標示了臨界區。典型的用法以下:安全

      synchronized(鎖){   //這個鎖是共享對象多線程

           臨界區代碼   併發

      }ide

    3. /**
       * 兩個線程共同打印a~z,考慮線程安全
       *
       */
      public class PrintLetters implements Runnable {
      
      	private char c = 'a';
      	
      	public synchronized boolean print() {
      		
      		if (c <= 'z') {
      			System.out.println(Thread.currentThread().getName() + " --- " + c);
      			
      			try {
      				Thread.currentThread().sleep(100);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      			}
      			
      			c++;
      			
      			return true;
      		}
      		
      		return false;
      	}
      	
      	@Override
      	public void run() {
      		boolean flag = print();
      		
      		while (flag) {
      			flag = print();
      		}
      
      	}
      
      	public static void main(String[] args) {
      		PrintLetters printLetters = new PrintLetters();
      		
      		Thread thread1 = new Thread(printLetters);
      		Thread thread2 = new Thread(printLetters);
      		
      		thread1.setName("線程-1");
      		thread2.setName("線程-2");
      		
      		thread1.start();
      		thread2.start();
      	}
      }

      上面代碼屬於public synchronized void add(int num)狀況,其鎖就是這個方法所在的對象。同理,若是方法是public  static synchronized void add(int num),那麼鎖就是這個方法所在的class。spa

  2. 線程間的相互做用:線程之間須要一些協調通訊,來共同完成一件任務。能夠調用java.lang.Object中的wait()、notify()和notifyAll()方法,這些方法是final的,不能被重寫。.net

    1. wait():使當前線程進入放棄對象鎖進入wait pool中等待。直到其餘線程調用notify()或notifyAll()方法喚醒該線程。要確保線程調用wait()方法時擁有對象鎖,即wait()方法必須在synchronized方法或者synchronized方法塊中調用。
      線程

    2. notify()、notifyAll()code

      1. notify():喚醒一個處於等待當前對象鎖的線程。若是多個線程處於等待狀態,會隨機選擇一個線程喚醒。同時,被喚醒的線程暫時不能被執行,須要等到當前線程放棄對象鎖。見:http://my.oschina.net/u/1757476/blog/420169  線程的生命週期。

      2. notifyAll():喚醒全部等待當前對象鎖的線程,變成等待該對象上的鎖。一旦該對象被解鎖,它們就會去競爭。

      3. /**
         * 模擬賣票:劉、關、張三人買票,售票員只有一張5元零錢,票價5元;張飛拿20元排在劉、關前面,劉、關二人各拿了5元。
         * 線程間的通訊
         */
        public class TicketHouse implements Runnable {
        	
        	private int fiveCount = 1, tenCount = 0, twentyCount = 0;
        	
        	public synchronized void buy() {
        		String name = Thread.currentThread().getName();
        		
        		//張飛 20元
        		if ("張飛".equals(name)) {
        			if (fiveCount < 3) {
        				try {
        					System.out.println("5元面值:" + fiveCount + ". 張飛等待...");
        					wait();
        					
        					System.out.println("賣一張票給" + name + ",找零15. 5元面值:" + fiveCount);
        				} catch (InterruptedException e) {
        					e.printStackTrace();
        				}
        			}
        		} else if ("關羽".equals(name) || "劉備".equals(name)) {
        			fiveCount++;
        			System.out.println("賣一張票給" + name + ",錢正好. 5元面值:" + fiveCount);
        		}
        		
        		if (fiveCount == 3) {
        			notifyAll();
        		}
        	}
        
        	@Override
        	public void run() {
        		buy();
        	}
        
        	public static void main(String[] args) {
        		Runnable runnable = new TicketHouse();
        		
        		Thread th1 = new Thread(runnable);
        		Thread th2 = new Thread(runnable);
        		Thread th3 = new Thread(runnable);
        		
        		th1.setName("劉備");
        		th2.setName("關羽");
        		th3.setName("張飛");
        		
        		th3.start();
        		th1.start();
        		th2.start();
        	}
        }
      4. /**
         * 兩個線程交替打印a~z
         *
         */
        public class PrintLetters2 implements Runnable {
        	private char c = 'a';
        	
        	@Override
        	public void run() {
        		while (c <= 'z') {
        			print();
        		}
        	}
        	
        	public synchronized void print() {
        		if (c <= 'z') {
        			System.out.println(Thread.currentThread().getName() + "---" + c);
        			c++;
        			
        			notify();
        			
        			try {
        				wait();
        			} catch (InterruptedException e) {
        				e.printStackTrace();
        			}
        		}
        	}
        	
        	public static void main(String[] args) {
        		Runnable runnable = new PrintLetters2();
        		
        		Thread th1 = new Thread(runnable);
        		Thread th2 = new Thread(runnable);
        		
        		th1.setName("線程-1");
        		th2.setName("線程-2");
        		
        		th1.start();
        		th2.start();
        	}
        }
相關文章
相關標籤/搜索