面試題 - 使用線程交替打印奇數偶數

這世上有三樣東西是別人搶不走的:一是吃進胃裏的食物,二是藏在心中的夢想,三是讀進大腦的書java

  • 分析題目。須要使用兩個線程交替打印奇偶數。
    • 使用同步鎖解決這個問題
    • 使用信號量來實現交替打印
  • 定義兩個信號量,一個奇數信號量,一個偶數信號量,都初始化爲1
  • 先用掉偶數的信號量,由於要讓奇數先啓動,等奇數打印完再釋放

信號量實現

  • 具體實現思路:
    • 定義兩個信號量,一個奇數信號量,一個偶數信號量,都初始化爲1
    • 先用掉偶數的信號量,由於要讓奇數先啓動,等奇數打印完再釋放
    • 具體流程就是 第一次的時候先減掉偶數的信號量 奇數線程打印完成之後用掉奇數的信號量。而後釋放偶數的信號量如此循環
import java.util.concurrent.Semaphore;

/**
 * @ClassName AlternatePrinting
 * @Author yunlogn
 * @Date 2019/5/21 
 * @Description 交替打印奇偶數
 */
public class AlternatePrinting {

	static int i = 0;
	public static void main(String[] args) throws InterruptedException {

      Semaphore semaphoreOdd = new Semaphore(1);
		 Semaphore semaphoreEven = new Semaphore(1);

      semaphoreOdd.acquire();  //讓奇數先等待啓動,因此先減掉偶數的信號量 等奇數線程來釋放

		SemaphorePrintEven semaphorePrintEven = new SemaphorePrintEven(semaphoreOdd, semaphoreEven);
		Thread t1 = new Thread(semaphorePrintEven);
		t1.start();

		SemaphorePrintOdd semaphorePrintOdd = new SemaphorePrintOdd(semaphoreOdd, semaphoreEven);
		Thread t2 = new Thread(semaphorePrintOdd);
		t2.start();

	}

	/**
	 * 使用信號量實現
	 */
	static class SemaphorePrintOdd implements Runnable {

		private Semaphore semaphoreOdd;
		private Semaphore semaphoreEven;


		public SemaphorePrintOdd(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
			this.semaphoreOdd = semaphoreOdd;
			this.semaphoreEven = semaphoreEven;
		}

		@Override
		public void run() {
			try {
            
				semaphoreOdd.acquire();//獲取信號量 semaphoreOdd在初始化的時候被獲取了信號量因此這裏被阻塞了,因此會先執行下面的奇數線程
				while (true) {
					i++;
					if (i % 2 == 0) {
						System.out.println("偶數線程:" + i);
						semaphoreEven.release();//釋放偶數信號量 讓奇數線程那邊的阻塞解除
						//再次申請獲取偶數信號量,由於以前已經獲取過,若是沒有奇數線程去釋放,那麼就會一直阻塞在這,等待奇數線程釋放
						semaphoreOdd.acquire();
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	static class SemaphorePrintEven implements Runnable {


		private Semaphore semaphoreOdd;
		private Semaphore semaphoreEven;


		public SemaphorePrintEven(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
			this.semaphoreOdd = semaphoreOdd;
			this.semaphoreEven = semaphoreEven;
		}

		@Override
		public void run() {

			try {
          
           
				semaphoreEven.acquire(); 
				while (true) {
					i++;
					if (i % 2 == 1) {
						System.out.println("奇數線程:" + i);
						semaphoreOdd.release(); //釋放奇數信號量 讓偶數線程那邊的阻塞解除
						
                //這裏阻塞,等待偶數線程釋放信號量
                //再次申請獲取奇數信號量,須要等偶數線程執行完而後釋放該信號量,否則阻塞
                semaphoreEven.acquire();
					}
				}

			} catch (Exception ex) {}


		}
	}
}

複製代碼
  • 須要注意的是,若是某個線程來不及釋放就異常中斷了,會致使另外一個線程一直在等,形成死鎖。 雖然這個異常不在這個問題的考慮範圍內 可是能夠使用finally 來包裹釋放鎖資源

同步鎖打印

  • 讓兩個線程使用同一把鎖。交替執行 。
    • 判斷是否是奇數 若是是奇數進入奇數線程執行打印並加一。而後線程釋放鎖資源。而後讓該線程等待
    • 判斷是否是偶數,若是是偶數進入偶數線程執行打印並加一。而後線程釋放鎖資源。而後讓該線程等待
import java.util.concurrent.atomic.AtomicInteger;


/**
 * @ClassName AlternatePrinting
 * @Author yunlogn
 * @Date 2019/5/21
 * @Description 交替打印奇偶數
 */
public class AlternatePrinting {

	public static AtomicInteger atomicInteger = new AtomicInteger(1);

	public static void main(String[] args) throws InterruptedException {

		Thread a=new Thread(new AThread());
		Thread b=new Thread(new BThread());
		a.start();
		b.start();

	}


	public static class AThread implements Runnable {

		@Override
		public void run() {
			while (true) {
				synchronized (atomicInteger) {
					if (atomicInteger.intValue() % 2 != 0) {
						System.out.println("奇數線程:" + atomicInteger.intValue());
						atomicInteger.getAndIncrement();
						// 奇數線程釋放鎖資源
						atomicInteger.notify();
						try {
							atomicInteger.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					} else {
						try {
							// 奇數線程等待
							atomicInteger.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}

	public static class BThread implements Runnable {

		@Override
		public void run() {
			while (true){
				synchronized (atomicInteger){
					if(atomicInteger.intValue() %2== 0 ){
						System.out.println("偶數線程:"+ atomicInteger.intValue());
						atomicInteger.getAndIncrement();
						// 偶數線程釋放鎖資源
						atomicInteger.notify();
						try {
							atomicInteger.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}else{
						try {
							// 偶數線程等待
							atomicInteger.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}

}

複製代碼
相關文章
相關標籤/搜索