• <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • Java面向對象
    Java異常
    Java數組
    Java常用類
    Java集合
    Java IO流
    Java線程
    Java反射
    Socket編程
    Java注解開發
    Java GoF設計模式
    HashMap
    Java內存模型
    Java線性表

    Java線程同步

     

     

    線程安全問題

     

    在多線程程序中,當多個線程同時操作堆區/方法區同一個數據時,可能引發數據不一致的現象, 稱為線程安全問題。

     

     

    出現線程安全問題, 怎么辦?

     

    讓每個線程都訪問自己的局部變量, 不會產生線程安全問題

     

    如果多個線程必須同時操作堆區/方法區同一個數據 , 采用線程同步技術

     

     

    線程如何同步?

     

    語法:

    synchronized ( 鎖對象 ) {
    
    同步代碼塊
    
    }

     

    工作原理:

     

    ● 線程要執行同步代碼塊,必須先獲得鎖對象

     

    ● 任意對象都可以作為鎖對象, 任意對象都有一個內置鎖

     

    ● 一個鎖對象最多被一個線程持有

     

    ● 線程持有了鎖對象后,會一直持有, 直到執行完同步代碼塊后才會釋放鎖對象

     

    package com.wkcto.chapter07.sync.p2;
    /**
     * 銀行帳戶類
     * @author 蛙課網
     *
     */
    public class BankAccount {
    	int balance = 10000 ; 			//余額 ,單位:萬元
    	private static final Object OBJ = new Object(); 		//常量
    	
    	//取錢的操作, 約定, 每次取錢1000
    	public void withdraw() {
    		synchronized ( OBJ ) { 		//一般使用常量作為鎖對象
    			System.out.println(Thread.currentThread().getName() +  "取錢 前, 余額為:" + balance);
    			balance -= 1000;
    			System.out.println(Thread.currentThread().getName() + "取了1000萬后, 余額為:" + balance);
    		}
    		/*
    		 * 1) xiaoming獲得了CPU執行權, 執行withdraw()方法, 先獲得OBJ鎖對象, 執行同步代碼塊
    		 * 2) xiaoming在執行同步代碼塊期間, CPU執行權被baby搶走了, xiaoming轉為就緒狀態
    		 * 		babay獲得CPU執行權, 要也執行同步代碼塊, 必須先獲得OBJ鎖對象,
    		 * 		現在OBJ鎖對象被xiaoming持有, baby線程轉到等待鎖對象池中阻塞
    		 * 3) xiaoming重新獲得CPU執行權, 繼續執行同步代碼塊, 執行完同步代碼塊后, 釋放OBJ鎖對象
    		 * 4) 等待鎖對象池中的baby如果獲得了鎖對象, 轉為就緒狀態
    		 */
    	}
    	
    }
    

     

    package com.wkcto.chapter07.sync.p2;
    /**
     * 定義一個線程類,模擬 從銀行帳戶 中取錢
     * @author 蛙課網
     *
     */
    public class PersonThread extends Thread {
    	private BankAccount bankaccount; 		//銀行帳戶 
    	
    	public PersonThread(BankAccount bankaccount) {
    		super();
    		this.bankaccount = bankaccount;
    	}
    
    	@Override
    	public void run() {
    		bankaccount.withdraw();
    	}
    }

     

    package com.wkcto.chapter07.sync.p2;
    /**
     * 使用線程模擬多人同時從某一帳戶中取錢
     * 	線程同步
     * @author 蛙課網
     *
     */
    public class Test01 {
    
    	public static void main(String[] args) {
    		//先開戶
    		BankAccount account = new BankAccount();
    		
    		//定義三個線程模擬三個人, 是從同一個帳戶中取錢 
    		PersonThread xiaoming = new PersonThread(account);
    		PersonThread bingbing = new PersonThread(account);
    		PersonThread baby = new PersonThread(account);
    		
    		xiaoming.setName("xiaoming");
    		bingbing.setName("bingbing");
    		baby.setName("baby");
    		
    		xiaoming.start();
    		bingbing.start();
    		baby.start();
    		
    	}
    
    }

     

     

    同步代碼塊

     

    同步代碼塊要想實現同步,必須保證使用同一個鎖對象

     

    只要使用了同一個鎖對象的同步代碼塊就可以同步

     

    package com.wkcto.chapter07.sync.p3;
    /**
     * 同步代碼塊, 只要使用相同的鎖對象就可以實現同步
     * @author 蛙課網
     *
     */
    public class Test01 {
    	public static void main(String[] args) {
    		PrintNum pNum = new PrintNum();
    		
    		//創建線程,調用m1()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				pNum.m1();
    			}
    		}).start();
    		
    		//創建線程,調用m2()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    //				pNum.m2();			//當使用this對象作為鎖對象時, 可以同步
    				new PrintNum().m2();  //使用this作為鎖對象, 不能同步,  與第一個線程的鎖對象不是一個
    			}
    		}).start();
    	}
    }

     

    package com.wkcto.chapter07.sync.p3;
    /**
     * 定義類
     * 	提供兩個 方法,分別打印字符串
     * @author 蛙課網
     *
     */
    public class PrintNum {
    	private static final Object OBJ = new Object(); 		//定義常量 
    	
    	public void m1() {
    //		synchronized (OBJ) {			//經常使用常量作為鎖對象
    		synchronized ( this ) {			//有時也會使用this作為鎖對象 , 就是調用m1()方法的對象
    			for(int i = 1; i<=200; i++){
    				System.out.println("wkcto is NB website");
    			}			
    		}
    	}
    	
    	public void m2() {
    //		synchronized (OBJ) {
    		synchronized (this) {
    			for(int i = 1; i<=200; i++){
    				System.out.println("bjpowernode is a good school");
    			}
    			
    		}
    	}
    }

     

    ackage com.wkcto.chapter07.sync.p4;
    /**
     * 使用當前類的運行時類作為鎖對象
     * @author 蛙課網
     *
     */
    public class Test02 {
    
    	public static void main(String[] args) {
    		//創建線程, 打印wkcto
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				while( true ){
    					printText("wkcto");
    				}
    			}
    		}).start();
    		
    		//創建線程, 打印bjpowernode
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				while( true ){
    					printText("bjpowernode");
    				}
    			}
    		}).start();
    	}
    
    	private static final Object OBJ = new Object();	//常量 
    	
    	//靜態方法,打印一個字符串
    	public static void printText( String  text) {
    //		synchronized (OBJ) {
    		synchronized ( Test02.class ) {  	//使用當前類的運行時類對象作為鎖對象, 有人把它稱為類鎖
    											//可以簡單的理解 為把當前類的字節碼文件作為鎖對象
    			for( int i = 0 ; i<text.length() ; i++){
    				System.out.print( text.charAt(i));
    			}
    			System.out.println();
    		}
    		
    	}
    }

     

     

    同步方法

     

    package com.wkcto.chapter07.sync.p5;
    /**
     * 同步實例方法, 就是把整個方法體作為同步代碼塊, 默認鎖對象 是this對象
     */
    public class Test01 {
    
    	public static void main(String[] args) {
    		Test01 obj = new Test01();
    		
    		//創建線程, 調用m1()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				obj.m1();
    			}
    		}).start();
    		
    		//創建線程, 調用m2()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				obj.m2();
    			}
    		}).start();
    		
    	}
    	
    	/*
    	 * 把整個方法體作為同步代碼塊,并且使用this作為鎖對象時, 可以直接使用synchronized修飾方法, 稱為同步方法 
    	 * 同步實例方法, 就是把整個方法體作為同步代碼塊, 默認鎖對象 是this對象
    	 */
    	public synchronized void m1() {
    		for(int i =1; i<=500; i++){
    			System.out.println( Thread.currentThread().getName() + "-->" + i);
    		}
    	}
    	
    	public void m2() {
    		synchronized ( this ) {
    			for(int i =1; i<=500; i++){
    				System.out.println( Thread.currentThread().getName() + "======>" + i);
    			}
    		}
    	}
    
    }

     

    package com.wkcto.chapter07.sync.p5;
    /**
     * 同步靜態方法, 就是把整個方法體作為同步代碼塊, 默認鎖對象 是當前類的運行時類對象
     */
    public class Test02 {
    
    	public static void main(String[] args) {
    		
    		//創建線程, 調用m1()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				Test02.m1();
    			}
    		}).start();
    		
    		//創建線程, 調用m2()
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				Test02.m2();
    			}
    		}).start();
    		
    	}
    	
    	/*
    	 * 把整個方法體作為同步代碼塊,并且使用當前類的運行時類對象(Test02.class)作為鎖對象時, 可以直接使用synchronized修飾方法, 稱為同步方法 
    	 * 同步靜態方法, 就是把整個方法體作為同步代碼塊, 默認鎖對象 是當前類的運行時類對象(Test02.class)
    	 */
    	public synchronized static void m1() {
    		for(int i =1; i<=500; i++){
    			System.out.println( Thread.currentThread().getName() + "-->" + i);
    		}
    	}
    	
    	public static void  m2() {
    		synchronized ( Test02.class ) {
    			for(int i =1; i<=500; i++){
    				System.out.println( Thread.currentThread().getName() + "======>" + i);
    			}
    		}
    	}
    
    }

     

    全部教程
  • <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • 面对面棋牌游戏