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 广东

相关推荐

05-24 10:30
已编辑
上海大学 Java
先做两张试卷的笔试,选择题、问答题、代码题、智力题,有的题的概念没碰到过。笔试二十分钟,面试四十分钟。1.&nbsp;自我介绍2.&nbsp;cs61b就是纯英文文档吗?3.&nbsp;知道哪些集合?4.&nbsp;hashmap线程安全吗?什么是线程安全的?5.&nbsp;讲讲concurrenthashmap的原理6.&nbsp;linkedlist线程安全吗?什么是线程安全的?7.&nbsp;校园go速递(苍穹)这个项目是怎么做的?8.&nbsp;redis在项目中怎么用的?9.&nbsp;AOP切面在项目中起了什么作用?填充了哪些字段?10.&nbsp;AOP可以针对哪些对象?11.&nbsp;java反射在哪里会用到?12.&nbsp;反射得到的是什么对象?13.&nbsp;WebSocket在项目中起了什么作用?14.&nbsp;通常什么场景使用WebSocket?15.&nbsp;对于WebSocket的心跳保持是如何做的?16.&nbsp;讲讲IOC控制反转17.&nbsp;@autowired和@resources的区别18.&nbsp;实例对象除了@bean还要加什么注解?19.&nbsp;常用的注解还有哪些?作用是什么?20.&nbsp;说说redis的五种数据类型,使用场景分别是什么?21.&nbsp;项目中redis用的是哪种数据类型?22.&nbsp;json对象怎么存到string类型的redis中?23.&nbsp;数据有修改,如何处理redis和数据库中的数据?24.&nbsp;项目中处理金额用的什么数据类型?25.&nbsp;怎么把一个float类型的数据转为bigDecimal类型?26.&nbsp;可以使用long类型去储存金额吗?27.&nbsp;场景题:有一个用户提现100元,他的余额只有100,如何在用户多次点击提现按钮的情况下,实现幂等,你如何处理?28.&nbsp;redis的事务和mysql事务有什么区别?29.&nbsp;synchronized锁了解吗?30.&nbsp;锁住的是什么?31.&nbsp;为了防止超卖有什么好的解决方法?32.&nbsp;讲讲mysql索引优化33.&nbsp;场景题:select&nbsp;a,b,c&nbsp;from&nbsp;table&nbsp;where&nbsp;c&nbsp;and&nbsp;d&nbsp;...&nbsp;,应该如何建索引?34.&nbsp;对于防止sql注入,用#还是$?35.&nbsp;$防止注入的原理是什么?36.&nbsp;使用$相比于&nbsp;,哪些用$?37.&nbsp;limit(...&nbsp;,&nbsp;...)有用过吗?原理是什么?38.&nbsp;假如limit(m,n),一共查了几次数据?39.&nbsp;mysql聚簇索引和非聚簇索引了解吗?40.&nbsp;nginx代理的原理,有什么用?41.&nbsp;自己配置过nginx相关文件吗?42.&nbsp;nginx反向代理和正向代理有什么区别?43.&nbsp;Linux命令用过哪些?44.&nbsp;docker命令用过哪些?45.&nbsp;docker要看目前正在运行的容器,用什么命令?46.&nbsp;有通过命令行进入docker内部看过吗?47.&nbsp;场景题:服务器qps无法承受很高流量,应该做什么措施?48.&nbsp;反问
点赞 评论 收藏
分享
头像
05-08 13:01
已编辑
华南师范大学 Java
&nbsp;&nbsp;🧠个人背景与实习1.你现在是本科还是研究生?2.你在XXX实习过是吧?3.你在这家公司主要做了什么?4.你这个项目是学校安排的吗?还是外部企业的真实项目?5.除了XXX系统这个例子,还有别的可以分享的项目吗?💻&nbsp;技术能力&nbsp;-&nbsp;后端开发数据库与SQL6.你说做了数据库优化,具体怎么优化的?7.什么是回表?8.全表扫描和走索引哪个更快?9.MySQL&nbsp;有哪些存储引擎?InnoDB&nbsp;和&nbsp;MyISAM&nbsp;有什么区别?☕Java&nbsp;&amp;&nbsp;Spring10.有没有用过线程池?11.线程池相关参数你了解哪些?最大线程数、核心线程数、keepAliveTime?12.用过什么线程安全的集合?13.如果想改&nbsp;Spring&nbsp;的源码怎么操作?14.你能定义一个和&nbsp;JDK&nbsp;里的&nbsp;String&nbsp;同名的类吗?🌐&nbsp;计算机网络15.TCP&nbsp;怎么保证可靠性?16.TCP&nbsp;的三次握手流程?17.第三次握手丢包怎么办?18.第三次握手丢包客户端怎么感知?19.第三次握手完成后是否还需等待服务器回应?20.HTTP&nbsp;常见方法有哪些?21.GET&nbsp;和&nbsp;POST&nbsp;有什么区别?22.GET&nbsp;和&nbsp;POST&nbsp;在参数传递、安全性上有什么不同?23.HTTP&nbsp;状态码含义(401、403、404、400、500)🖥️&nbsp;Linux&nbsp;系统与命令24.你会&nbsp;Linux&nbsp;吗?25.如何在&nbsp;vi&nbsp;里替换字符(oldStr→newStr)?26.用什么命令查日志中含某个关键字的错误?(find、grep)27.你知道&nbsp;AWK&nbsp;是做什么用的吗?用过吗?☁️&nbsp;分布式与系统架构28.你怎么理解分布式系统?29.Spring&nbsp;Cloud&nbsp;是做什么的?30.你对分布式架构掌握到什么程度?🧪&nbsp;学习能力与动机31.你学习这些技术的来源是什么?32.你是怎么规划自己的学习路径的?
点赞 评论 收藏
分享
评论
2
11
分享

创作者周榜

更多
牛客网
牛客企业服务