1. 程式人生 > >synchronized 解析使用

synchronized 解析使用

java鎖分為物件鎖,類鎖,

synchronized就是熟知的程式碼同步塊。

加鎖一個方法塊,根據鎖的機制上鎖的只是這個物件,

package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer extends Thread{
	  int num=1;
	public synchronized int count() {
		
			while(num<10) {
			System.out.println(Thread.currentThread() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(500);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
		return num;
		
	}
	
	public void run() {
		count();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Producer aProducer=new Producer();
		Producer bProducer=new Producer();
		aProducer.start();
		bProducer.start();
	}

}

輸出為這樣

Thread[Thread-1,5,main]   1
Thread[Thread-0,5,main]   1
Thread[Thread-0,5,main]   2
Thread[Thread-0,5,main]   3
Thread[Thread-0,5,main]   4
Thread[Thread-0,5,main]   5
Thread[Thread-0,5,main]   6
Thread[Thread-0,5,main]   7
Thread[Thread-0,5,main]   8
Thread[Thread-0,5,main]   9
Thread[Thread-1,5,main]   2
Thread[Thread-1,5,main]   3
Thread[Thread-1,5,main]   4
Thread[Thread-1,5,main]   5
Thread[Thread-1,5,main]   6
Thread[Thread-1,5,main]   7
Thread[Thread-1,5,main]   8
Thread[Thread-1,5,main]   9


說明如果只是對方法上鎖的話,那麼實際上會對當前的物件上鎖,而我們實現了兩個物件,所以並沒有實現同步。

package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer extends Thread{
	  int num=1;
	public  int count() {
		synchronized (this) {
			while(num<10) {
			System.out.println(Thread.currentThread() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(500);
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
		
		return num;
		
	}
	
	public void run() {
		count();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Producer aProducer=new Producer();
		Producer bProducer=new Producer();
		aProducer.start();
		bProducer.start();
	}

}

對當前物件進行上鎖  輸出結果依舊為沒有上鎖的樣子
Thread[Thread-0,5,main]   1
Thread[Thread-1,5,main]   1
Thread[Thread-0,5,main]   2
Thread[Thread-1,5,main]   2
Thread[Thread-0,5,main]   3
Thread[Thread-0,5,main]   4
Thread[Thread-0,5,main]   5
Thread[Thread-0,5,main]   6
Thread[Thread-0,5,main]   7
Thread[Thread-0,5,main]   8
Thread[Thread-0,5,main]   9
Thread[Thread-1,5,main]   3
Thread[Thread-1,5,main]   4
Thread[Thread-1,5,main]   5
Thread[Thread-1,5,main]   6
Thread[Thread-1,5,main]   7
Thread[Thread-1,5,main]   8
Thread[Thread-1,5,main]   9

那對於兩個不同的執行緒物件 我們要上鎖的其實就是公有的屬性,或者說就是靜態屬性。
package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer extends Thread{
	 static int num=1;
	public  int count() {
		synchronized (Producer.class) {
			while(num<10) {
			System.out.println(Thread.currentThread() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(500);
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
		
		return num;
		
	}
	
	public void run() {
		count();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Producer aProducer=new Producer();
		Producer bProducer=new Producer();
		aProducer.start();
		bProducer.start();
	}

}


Thread[Thread-1,5,main]   1
Thread[Thread-1,5,main]   2
Thread[Thread-1,5,main]   3
Thread[Thread-1,5,main]   4
Thread[Thread-1,5,main]   5
Thread[Thread-1,5,main]   6
Thread[Thread-1,5,main]   7
Thread[Thread-1,5,main]   8
Thread[Thread-1,5,main]   9

如果是兩個物件操作靜態變數,對XX.class進行上鎖就可以實現,對類上鎖同步靜態變數方法以及常量。

對於靜態方法的synchronized就相當於給這個方法所在的這個記憶體塊添加了一個監視器,

在類載入的時候,類的基本資訊和一些常量和今天變數都儲存在jvm記憶體的方法區,

對synchronized(XX.class)  就等於對這個類的所有資訊加上 監視器,一個執行緒進行訪問計數+1,釋放-1,不為0就一直阻塞其他執行緒訪問。

而類初始化的例項物件則放在了jvm記憶體的堆區

而對例項物件的上鎖就相當於監視這個例項物件,而不同的物件在不同塊  並不能實現同步。

對於同一個物件例項

未上鎖時

package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer {
	 int num=1;
	public  int count() {
		
			while(num<10) {
			System.out.println(Thread.currentThread().getName() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(1000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
	
		return num;
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		final Producer aProducer=new Producer();
		//Producer bProducer=new Producer();
		Thread test1=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		});
		Thread test2=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		});
		test1.start();
		
		test2.start();
		//bProducer.start();
	}

}


Thread-0   1
Thread-1   1
Thread-0   2
Thread-1   3
Thread-0   4
Thread-1   5
Thread-0   6
Thread-1   7
Thread-0   8
Thread-1   9

對其當前物件上鎖
package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer {
	 int num=1;
	public  int count() {
		synchronized (this) {		
			while(num<10) {
			System.out.println(Thread.currentThread().getName() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(1000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
		}
		return num;
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		final Producer aProducer=new Producer();
		//Producer bProducer=new Producer();
		Thread test1=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		});
		Thread test2=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		});
		test1.start();
		
		test2.start();
		//bProducer.start();
	}

}

Thread-0   1
Thread-0   2
Thread-0   3
Thread-0   4
Thread-0   5
Thread-0   6
Thread-0   7
Thread-0   8
Thread-0   9

由於num一直由第一個執行緒執行沒有釋放,所以第二個執行緒由於大於10直接結束。

直觀一點 

num宣告在方法內

package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer {
	
	public  int count() {
		 int num=1;
		synchronized (this) {		
			while(num<10) {
			System.out.println(Thread.currentThread().getName() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(1000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
		}
		return num;
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		 final Producer aProducer=new Producer();
		//Producer bProducer=new Producer();
		Thread test1=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		},"test1");
		Thread test2=new Thread(new Runnable() {
			
			@Override
			public void run() {
				aProducer.count();
				
			}
		},"test2");
		test1.start();
		
		test2.start();
		//bProducer.start();
	}

}


輸出就為這樣

test2   1
test2   2
test2   3
test2   4
test2   5
test2   6
test2   7
test2   8
test2   9
test1   1
test1   2
test1   3
test1   4
test1   5
test1   6
test1   7
test1   8
test1   9

簡單的生產者消費者模型

package hw.lock;

/**
 * 
 * 
 * @author huangwei
 *	2017 10 20 
 */
public class Producer {
	int pnum=0;
	public  int count() {
		 int num=1;
		synchronized (this) {		
			while(num<10) {
			System.out.println(Thread.currentThread().getName() +"   "+num++);//輸出當前執行緒
			}
			
			
			try {
			Thread.sleep(5000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
		}
		return num;
		
	}

	
	public void produce() {//生產者
		synchronized (this) {
			try {
			if(pnum>10) {
				this.wait();//數量上限等待
			}
			this.notify();//喚醒程序
			pnum++;
			System.out.println("生產者生產:1,還剩下:"+this.pnum);
			
				Thread.sleep(1000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
		
		
	}
	
	public void customer() {//消費者
		synchronized (this) {
			try {
			if(pnum>0) {
				this.notify();//可以取  喚醒
				pnum--;
				System.out.println("消費者消費:1,還剩下:"+this.pnum);
				}else{
					System.out.println("消費者消費:0,儲量不足");
					this.wait();//否則等待
				}
			
				Thread.sleep(1000);
			}catch (Exception e) {
				// TODO: handle exception
			}
		
		}
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		 final Producer aProducer=new Producer();
		//Producer bProducer=new Producer();
		Thread test1=new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
				aProducer.produce();
				}
			}
		},"test1");
		Thread test2=new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
				aProducer.customer();
				}
			}
		},"test2");
		test1.start();
		
		test2.start();
		
		//bProducer.start();
	}

}

生產者生產:1,還剩下:1
消費者消費:1,還剩下:0
消費者消費:0,儲量不足
生產者生產:1,還剩下:1
生產者生產:1,還剩下:2
生產者生產:1,還剩下:3
生產者生產:1,還剩下:4
消費者消費:1,還剩下:3
生產者生產:1,還剩下:4
生產者生產:1,還剩下:5
生產者生產:1,還剩下:6
消費者消費:1,還剩下:5
消費者消費:1,還剩下:4
消費者消費:1,還剩下:3
生產者生產:1,還剩下:4
生產者生產:1,還剩下:5
生產者生產:1,還剩下:6
生產者生產:1,還剩下:7