Synchronize 對象鎖,類鎖,重入鎖

一、對象鎖和類鎖
1、線程安全:當多個線程訪問某一個類(對象或者方法),這個類始終能夠表現出正確的行爲,
  那麼此類(對象或者方法)是線程安全的
  synchronized:可以在任意對象或者方法上加鎖,而加鎖的這段代碼稱爲‘互斥區’或者臨界區
2.對象鎖和類鎖具體參考:對象鎖和類鎖示例
3.髒讀:讀到了共享變量中未刷新的值

二、重入鎖
1、重入鎖:關鍵字synchronized擁有鎖重入的功能,在使用synchronized的時候,當一個線程得到了一個對象的鎖
  後,再次請求該對象時,是可以再次得到該對象的鎖,
2、重入鎖代碼示例:

/**
 * synchronized的重入
 */
public class SyncDubbo1 {

	public synchronized void method1(){
		System.out.println("method1..");
		method2();
	}
	public synchronized void method2(){
		System.out.println("method2..");
		method3();
	}
	public synchronized void method3(){
		System.out.println("method3..");
	}
	
	public static void main(String[] args) {
		final SyncDubbo1 sd = new SyncDubbo1();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				sd.method1();
			}
		});
		t1.start();
	}
}
/**
 * synchronized的重入
 */
public class SyncDubbo2 {

	static class Main {
		public int i = 10;
		public synchronized void operationSup(){
			try {
				i--;
				System.out.println("Main print i = " + i);
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	static class Sub extends Main {
		public synchronized void operationSub(){
			try {
				while(i > 0) {
					i--;
					System.out.println("Sub print i = " + i);
					Thread.sleep(100);		
					this.operationSup();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sub sub = new Sub();
				sub.operationSub();
			}
		});
		
		t1.start();
	}	
}

三、代碼塊鎖
1、代碼塊鎖示例:可以使用任意的Object加鎖,用法比較靈活,不要使用String的常量加鎖,會出現死循環的問題

/**
 * 使用synchronized代碼塊加鎖,比較靈活
 *
 */
public class ObjectLock {

	public void method1(){
		synchronized (this) {	//對象鎖
			try {
				System.out.println("do method1..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void method2(){		//類鎖
		synchronized (ObjectLock.class) {
			try {
				System.out.println("do method2..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private Object lock = new Object();
	public void method3(){		//任何對象鎖
		synchronized (lock) {
			try {
				System.out.println("do method3..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	public static void main(String[] args) {
		
		final ObjectLock objLock = new ObjectLock();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				objLock.method1();
			}
		});
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				objLock.method2();
			}
		});
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				objLock.method3();
			}
		});
		
		t1.start();
		t2.start();
		t3.start();
	}
	
}
/**
 * 同一對象屬性的修改不會影響鎖的情況
 *
 */
public class ModifyLock {
	
	private String name ;
	private int age ;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public synchronized void changeAttributte(String name, int age) {
		try {
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 開始");
			this.setName(name);
			this.setAge(age);
			
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 修改對象內容爲: " 
					+ this.getName() + ", " + this.getAge());
			
			Thread.sleep(2000);
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 結束");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		final ModifyLock modifyLock = new ModifyLock();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				modifyLock.changeAttributte("張三", 20);
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				modifyLock.changeAttributte("李四", 21);
			}
		},"t2");
		
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}
	
}

2、對象鎖屬性修改示例:鎖對象的改變問題,當還是用一個對象進行加鎖的時候,要注意對象本身是發生改變的時候,那麼持有的鎖就不同。如果對象本身不發生改變,那麼依然是同步的,即使是對象的屬性發生了改變

/**
 * 同一對象屬性的修改不會影響鎖的情況
 *
 */
public class ModifyLock {
	
	private String name ;
	private int age ;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public synchronized void changeAttributte(String name, int age) {
		try {
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 開始");
			this.setName(name);
			this.setAge(age);
			
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 修改對象內容爲: " 
					+ this.getName() + ", " + this.getAge());
			
			Thread.sleep(2000);
			System.out.println("當前線程 : "  + Thread.currentThread().getName() + " 結束");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		final ModifyLock modifyLock = new ModifyLock();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				modifyLock.changeAttributte("張三", 20);
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				modifyLock.changeAttributte("李四", 21);
			}
		},"t2");
		
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}
	
}

3、死鎖問題:死鎖問題,在設計程序時就應該避免雙方相互持有對方的鎖的情況
4.synchronized代碼塊對字符串的鎖,注意String常量池的緩存功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章