tx一面线程交替手撕

import java.util.concurrent.Semaphore;

// 交替打印   1 A  2 B 3 C 这样的线程
public class alternatingPrinter {

    public static Semaphore  text = new Semaphore(1);
    public  static  Semaphore  word=new Semaphore(0);
    public static   int maxText=3;
    public static  int maxWord='c';
    
    public static void main(String[] args) {
          Thread thread1=new Thread(new printerText());
          Thread thread2=new Thread(new printerWord());
          thread2.start();
          thread1.start();
    }
    static  class  printerText implements Runnable  {

        @Override
        public void run() {
            for (int i = 1; i <=maxText; i++) {
                try {
                    text.acquire();
                    System.out.println(i);
                    word.release();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static  class  printerWord implements  Runnable{

        @Override
        public void run() {
            for (int i = 'A'; i <=maxWord ; i++) {
               try {
                   //会一直等待这个信号量
                   word.acquire();
                   System.out.println((char)i);
                   text.release();
               }catch (InterruptedException e){
                   e.printStackTrace();
               }
            }
        }
    }
}

通过信号量来控制两个线程打印的顺序问题。

如果两个线程打印的长度不匹配, A1 B 2 C 3 D EF 这样的形式呢?

通过定义两个变量 boolean 类型的用来判断是否结束,如果结束了,如果对方结束了直接打印即可,就不用再释放锁了。


import java.util.concurrent.Semaphore;

// 交替打印   1 A  2 B 3 C 这样的线程
public class alternatingPrinter {

    public static Semaphore  text = new Semaphore(1);
    public  static  Semaphore  word=new Semaphore(0);

    public static   int maxText=10;
    public static  int maxWord='C';
    public  static  boolean isText=false;
    public  static  boolean isWord=false;
    public static void main(String[] args) {

        Thread thread1=new Thread(new printerText());
        Thread thread2=new Thread(new printerWord());

        thread2.start();
        thread1.start();
    }

    static  class  printerText implements Runnable  {

        @Override
        public void run() {
            for (int i = 1; i <=maxText; i++) {
                try {
                    if (isWord){
                        System.out.println(i);
                        continue;
                    }
                    text.acquire();
                    System.out.println(i);
                    word.release();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            isText=true;
            text.release();
        }
    }
    static  class  printerWord implements  Runnable{
        @Override
        public void run() {
            for (int i = 'A'; i <=maxWord ; i++) {
                try {
                    //会一直等待这个信号量
                    if (isText){
                        System.out.println(i);
                        continue;
                    }
                    word.acquire();
                    System.out.println((char)i);
                    text.release();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            isWord=true;
            word.release();
        }
    }
}

可重入锁是什么,可以使用可重入锁来实现交替打印吗?

可重入锁是允许同一个线程多次获得同一把锁的同步机制。

后台通过定义计数器来实现,释放锁的时候计数器递减,只有计数器为 0 的时候才是真正的释放。

在 Java 中主要是 ReentantLock 类,实现可重入锁,手动的进行 lock 和 unlock,实现细粒度的锁机制。

直接用 lock 无法控制两个线程交替打印,需要通过 Condition 来实现。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

 class alternatingPrinter2 {

    // 创建可重入锁及两个 Condition
    private static ReentrantLock lock = new ReentrantLock();
    // 数字线程等待条件
    private static Condition conditionNumber = lock.newCondition();
    // 字母线程等待条件
    private static Condition conditionLetter = lock.newCondition();
  
    private static boolean numberTurn = true;

    private static final int MAX_NUMBER = 3; // 打印数字 1~3
    private static final int MAX_LETTER = 'C'; // 打印字母 A~C

    public static void main(String[] args) {
        Thread threadNumber = new Thread(new NumberPrinter());
        Thread threadLetter = new Thread(new LetterPrinter());

        threadNumber.start();
        threadLetter.start();
    }

    // 打印数字的线程
    static class NumberPrinter implements Runnable {
        @Override
        public void run() {
            for (int i = 1; i <= MAX_NUMBER; i++) {
                lock.lock();
                try {
                    // 如果不是数字打印的时机,则等待
                    while (!numberTurn) {
                        conditionNumber.await();
                    }
                    // 打印数字
                    System.out.print(i + " ");
                    // 修改标志,轮到字母线程打印
                    numberTurn = false;
                    // 通知字母线程
                    conditionLetter.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    // 打印字母的线程
    static class LetterPrinter implements Runnable {
        @Override
        public void run() {
            for (char c = 'A'; c <= (char) MAX_LETTER; c++) {
                lock.lock();
                try {
                    while (numberTurn) {
                        conditionLetter.await();
                    }
                    System.out.print(c + " ");
          
                    numberTurn = true;
      
                    conditionNumber.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}
#交替打印#
牛牛的算法专栏 文章被收录于专栏

牛牛的算法专栏,记录一些算法题

全部评论
很妙
点赞 回复 分享
发布于 04-23 12:10 广东

相关推荐

📍面试公司:用友🕐面试时间:2024年6月12日💻面试岗位:JAVA实习❓面试问题:1.&nbsp;泛型在Java编程里的核心作用是什么,它怎样增强代码的灵活性与安全性?2.&nbsp;Java中多态通过哪些具体方式来实现,每种方式在实际开发中有何应用场景?3.&nbsp;面向接口编程为何能让代码具备更好的扩展性,举例说明在系统升级时的作用?4.&nbsp;MySQL里page类型按存储和功能划分,常见的具体类型有哪些?5.&nbsp;MySQL中脏页出现的原因是什么,数据库系统如何处理脏页以保障数据一致性?6.&nbsp;MySQL的刷盘策略中,哪种策略能在数据安全性和性能之间取得较好平衡,为什么?7.&nbsp;HTTPS协议建立安全连接的完整流程是怎样的,每个步骤起到什么作用?8.&nbsp;在进行大文件传输时,为保证数据可靠性,常用的校验和纠错机制有哪些?9.&nbsp;TLS协议在HTTPS通信中如何实现数据的加密和解密,密钥是如何管理的?10.&nbsp;MQTT协议适用于哪些物联网场景,它与其他消息协议相比优势在哪里?11.&nbsp;JVM在整个Java程序运行过程中承担什么关键角色,与普通Java程序有何关联?12.&nbsp;Java本地方法栈在JVM中有什么作用,它和虚拟机栈有什么本质区别?13.&nbsp;JVM运行时数据区里,方法区存储的具体内容是什么,对程序运行有何影响?14.&nbsp;Java类加载过程中,验证阶段主要验证哪些内容,为什么要进行这些验证?15.&nbsp;若要自定义一个类加载过程,需要实现哪些关键方法,如何控制类的加载顺序?16.&nbsp;JVM的GC原理中,标记清除算法存在什么缺陷,后续有哪些改进算法?17.&nbsp;操作系统一次读取数据的大小受哪些因素影响,不同存储设备有何差异?18.&nbsp;用户态和内核态切换的触发条件有哪些,这种切换对系统性能有何影响?19.&nbsp;项目中MQ和MySQL实现一致性时,分布式事务的常见解决方案有哪些,各有什么优缺点?20.&nbsp;AQS在Java并发编程里如何实现同步控制,核心思想是什么?🙌面试感想:这是我去年日常实习的一次面试,给大三上学期刚开始面试的我带来了不小的打击,纯粹的八股文盛宴,问的又偏又详细,当时还以为中大厂都是这种强度,心都凉了大半截
查看20道真题和解析
点赞 评论 收藏
分享
评论
2
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务