前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试题-使用线程交替打印奇数偶数

面试题-使用线程交替打印奇数偶数

作者头像
云扬四海
发布2019-06-05 17:32:22
1.3K0
发布2019-06-05 17:32:22
举报
文章被收录于专栏:云扬四海

这世上有三样东西是别人抢不走的:一是吃进胃里的食物,二是藏在心中的梦想,三是读进大脑的书

  • 分析题目。需要使用两个线程交替打印奇偶数。
    • 使用同步锁解决这个问题
    • 使用信号量来实现交替打印
  • 定义两个信号量,一个奇数信号量,一个偶数信号量,都初始化为1
  • 先用掉偶数的信号量,因为要让奇数先启动,等奇数打印完再释放

信号量实现

  • 具体实现思路:
    • 定义两个信号量,一个奇数信号量,一个偶数信号量,都初始化为1
    • 先用掉偶数的信号量,因为要让奇数先启动,等奇数打印完再释放
    • 具体流程就是 第一次的时候先减掉偶数的信号量 奇数线程打印完成以后用掉奇数的信号量。然后释放偶数的信号量如此循环
代码语言:javascript
复制
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 来包裹释放锁资源

同步锁打印

  • 让两个线程使用同一把锁。交替执行 。
    • 判断是不是奇数 如果是奇数进入奇数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
    • 判断是不是偶数,如果是偶数进入偶数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
代码语言:javascript
复制
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();
                        }
                    }
                }
            }
        }
    }

}

一种更简单的写法

代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-05-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 信号量实现
  • 同步锁打印
    • 一种更简单的写法
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档