zoukankan      html  css  js  c++  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();
    						}
    					}
    				}
    			}
    		}
    	}
    
    }
    
    

    一种更简单的写法

    public class TheadTest {
     
     
        public static void main(String[] args) {
            PrintDigitThread print1 = new PrintDigitThread((i) -> i % 2 == 1, "thread1");
            PrintDigitThread print2 = new PrintDigitThread((i) -> i % 2 == 0, "thread2");
            print1.start();
            print2.start();
        }
    }
     
    class ShareData {
        public static final AtomicInteger atomicInt = new AtomicInteger(0);
    }
     
    class PrintDigitThread extends Thread {
        private Predicate<Integer> predicate;
     
        public PrintDigitThread(Predicate<Integer> predicate, String name) {
            this.predicate = predicate;
            this.setName(name);
        }
     
        @Override
        public void run() {
            int v = ShareData.atomicInt.get();
            while (v < 100) {
                synchronized (ShareData.atomicInt) {
                    v = ShareData.atomicInt.get();
                    if (predicate.test(v)) {
                        System.out.println(Thread.currentThread().getName() + ":" + v);
                        ShareData.atomicInt.incrementAndGet();
                        try {
                            ShareData.atomicInt.notify();
                        } catch (Exception ex) {
     
                        }
                    } else {
                        try {
                            ShareData.atomicInt.wait();
                        } catch (Exception ex) {
     
                        }
                    }
                }
            }
        }
    }
    
    

    欢迎关注  http://yunlongn.github.io

  • 相关阅读:
    服务器负载均衡的基本功能和实现原理
    几种负载均衡技术的实现
    Postman-CI集成Jenkins
    Postman-进阶
    Postman-简单使用
    chrome安装插件,安装Postman
    关于angularjs dom渲染结束再执行的问题
    Protractor(angular定制的e2e)的简易入门
    关于ng-router嵌套使用和总结
    scss使用后的简单入门总结
  • 原文地址:https://www.cnblogs.com/rolandlee/p/10900149.html
Copyright © 2011-2022 走看看