線程同步的6種方法

1.synchronize

做用在靜態方法上和作用在代碼塊上(鎖對象是類名.class)效果一樣

public class SynThread1{
	
	public static void main(String[] args) {
		new Thread() {
			public void run() {
				print1();
			};
		}.start();
		new Thread() {
			public void run() {
				print2();
			};
		}.start();
	}

	public static synchronized void print1() {
		for(int i=0;i<5;i++) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.print(i+" ");
		}
		System.out.println();
	}
	
	public static void print2() {
		synchronized (SynThread1.class) {
			for(int i=5;i<10;i++) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.print(i+" ");
			}
			System.out.println();
		}
	}
}

結果
在這裏插入圖片描述

2.ReentrantLock重入鎖

lock()方法加鎖,unlock()釋放鎖。建議unlock()在finally語句塊中。

public class LockThread1 {
	static ReentrantLock lock = new ReentrantLock();
	
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				print1();
			}
		}).start();
		new Thread() {
			public void run() {
				print2();
			};
		}.start();
	}
	
	public static void print1() {
		for(int i=1;i<5;i++) {
			lock.lock();
			try {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.print(i);
			}finally {
				lock.unlock();
			}
		}
	} 
	public static void print2() {
		for(int i=5;i<9;i++) {
			lock.lock();
			try {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.print(i);
			}finally {
				lock.unlock();
			}
		}
	} 
}

結果
在這裏插入圖片描述

3.可能會同步的volatile

每次要線程要訪問volatile修飾的變量時都是從內存中讀取,而不是存緩存當中讀取,因此每個線程訪問到的變量值都是一樣的。但是它不保證同步,只是接近而已。運行了10次,其中8次同步。

public class VolThread1 {
	volatile static int a = 0;
	
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				add1();
				System.out.println(a);
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				add2();
				System.out.println(a);
			}
		}).start();
	}
	
	public static void add1() {
		for(int i=1;i<=10;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			a = a+i;
		}
	}
	
	public static void add2() {
		for(int i=1;i<=10;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			a = a+i;
		}
	}
}

正常結果
在這裏插入圖片描述
其中一個異常結果
在這裏插入圖片描述
不推薦的方法

4.Semaphore信號量(可參數設置幾個線程同時運行)

new Semaphore(int permits)參數是允許同時進行的線程數,如果線程未獲得准入許可,進入等待,acquire()方法嘗試獲得許可,release()方法釋放一個許可

public class SemThread1 {
	//控制同時運行的線程數
	final static Semaphore semap = new Semaphore(2);
	
	public static void main(String[] args) {
		new Thread() {
			public void run() {
				print1();
			};
		}.start();
		new Thread() {
			public void run() {
				print1();
			};
		}.start();
		new Thread() {
			public void run() {
				print2();
			};
		}.start();
	}
	
	public static void print1() {
		try {
			semap.acquire();
			for(int i=1;i<5;i++) {
				TimeUnit.SECONDS.sleep(1);
				System.out.print(i);
			}
			System.out.println();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			semap.release();
		}
	}
	
	public static void print2() {
		try {
			semap.acquire();
			for(int i=5;i<9;i++) {
				TimeUnit.SECONDS.sleep(1);
				System.out.print(i);
			}
			System.out.println();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			semap.release();
		}
	}
}

這裏的三個線程同時對多隻能運行兩個
結果
在這裏插入圖片描述

5.CountDownLatch門閂

new CountDownLatch(int count)指定門閂數,countDown()方法將門閂減一,await()方法等待門閂數減爲0。

public class LatchThread {
	
	final static CountDownLatch latch = new CountDownLatch(1);
	
	public static void main(String[] args) {
		new Thread() {
			public void run() {
				print1();
			};
		}.start();
		new Thread() {
			public void run() {
				print2();
			};
		}.start();
	}
	
	public static void print1() {
		for(int i=1;i<5;i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.print(i);
		}
		latch.countDown();
		System.out.println();
	}
	
	public static void print2() {
		try {
			latch.await();
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		for(int i=5;i<9;i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.print(i);
		}
		System.out.println();
	}
	
}

結果
在這裏插入圖片描述

6.FixedThreadPool定長線程池(多多少少算是吧)

Executors.newFixedThreadPool(int nThreads),nThreads指定可以有幾個線程同時運行,如果是1的話,也算是有同步的效果。。。execute(Runnable command)方法執行線程。超過指定的nThreads會進入阻塞隊列等待。

public class ExecutorThread {
	static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
	
	public static void main(String[] args) {
		fixedThreadPool.execute(new Runnable() {
			@Override
			public void run() {
				print1();
			}
		});
		fixedThreadPool.execute(new Runnable() {
			
			@Override
			public void run() {
				print2();
			}
		});
	}
	
	public static void print1() {
		for(int i=1;i<5;i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.print(i);
		}
		System.out.println();
	}
	
	public static void print2() {
		for(int i=5;i<9;i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.print(i);
		}
		System.out.println();
	}
}

結果
在這裏插入圖片描述

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