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

相关推荐

06-12 11:51
已编辑
门头沟学院 Java
1.&nbsp;反射的原理是什么?2.&nbsp;类加载时,类和实例分别加载到哪里?3.&nbsp;什么是好的编程方法或方案?4.&nbsp;SQL&nbsp;语句优化有哪些方法?5.&nbsp;订单生成&nbsp;ID&nbsp;的实现方式是什么?6.&nbsp;如何处理时间回拨问题?7.&nbsp;雪花算法的基本原理是什么?8.&nbsp;如何设计一个简单的&nbsp;IOC&nbsp;容器?9.&nbsp;自动装箱和拆箱的底层实现是什么?10.&nbsp;Java&nbsp;中的线程安全是什么意思?11.&nbsp;什么是&nbsp;TLAB(Thread&nbsp;Local&nbsp;Allocation&nbsp;Buffer)?12.&nbsp;NIO&nbsp;的基本概念是什么?13.&nbsp;ConcurrentHashMap&nbsp;中锁的机制是什么?14.&nbsp;一条&nbsp;SQL&nbsp;语句在&nbsp;MySQL&nbsp;中的执行过程是怎样的?15.&nbsp;MySQL&nbsp;中事务的日志记录是如何实现的?16.&nbsp;如何通过代码实现死锁?17.&nbsp;接口和抽象类的区别是什么?18.&nbsp;接口和抽象类在设计模式中的体现有哪些?19.&nbsp;String、StringBuilder&nbsp;和&nbsp;StringBuffer&nbsp;的区别是什么?20.&nbsp;final&nbsp;关键字的作用是什么?21.&nbsp;THREAD&nbsp;LOCAL&nbsp;可能引发的内存泄漏问题是什么?22.&nbsp;THREAD&nbsp;LOCAL&nbsp;的应用场景有哪些?23.&nbsp;如何将父线程的&nbsp;THREAD&nbsp;LOCAL&nbsp;值传递给子线程?24.&nbsp;对&nbsp;Java&nbsp;面向对象的理解是什么?25.&nbsp;面向对象和面向过程的区别是什么?26.&nbsp;Java&nbsp;中创建对象的方式有哪些?27.&nbsp;Java&nbsp;中序列化与反序列化的概念是什么?28.&nbsp;Redis&nbsp;中使用哈希存储对象和直接使用字符串存储对象的区别是什么?29.&nbsp;Java&nbsp;中参数传递是按值传递还是按引用传递?30.&nbsp;多继承可能带来的问题是什么?31.&nbsp;方法重载与方法重写的区别是什么?32.&nbsp;Java&nbsp;内部类的概念和作用是什么?33.&nbsp;JDK&nbsp;8&nbsp;的新特性有哪些?34.&nbsp;JRE&nbsp;和&nbsp;JDK&nbsp;的区别是什么?35.&nbsp;JDK&nbsp;中常用的工具类有哪些?36.&nbsp;Hashcode&nbsp;的作用是什么?37.&nbsp;TreeSet&nbsp;集合在加入一个对象时如何判断该对象是否存在?38.&nbsp;是否可能两个不相等的对象有相同的哈希值?39.&nbsp;Java&nbsp;中的&nbsp;hashCode&nbsp;和&nbsp;equals&nbsp;方法有什么区别?40.&nbsp;什么是&nbsp;Java&nbsp;中的动态代理?41.&nbsp;动态代理与静态代理的区别是什么?42.&nbsp;注解的原理是什么?43.&nbsp;SPI&nbsp;机制的作用是什么?44.&nbsp;泛型的作用是什么?45.&nbsp;什么是泛型擦除?46.&nbsp;深拷贝和浅拷贝的区别是什么?47.&nbsp;Integer&nbsp;类型的缓存池是如何工作的?48.&nbsp;Java&nbsp;程序的运行过程是怎样的?49.&nbsp;new&nbsp;一个&nbsp;String&nbsp;类型的对象时会创建多少个对象?50.&nbsp;final、finally&nbsp;和&nbsp;finalize&nbsp;的区别是什么?51.&nbsp;Java&nbsp;的基本类型有哪些?52.&nbsp;静态方法和实例方法的区别是什么?53.&nbsp;for-each&nbsp;循环实现的接口或集合类型是什么?54.&nbsp;RandomAccess&nbsp;接口的作用是什么?55.&nbsp;迭代器(Iterator)的工作原理是什么?56.&nbsp;ArrayList&nbsp;和&nbsp;LinkedList&nbsp;的区别是什么?57.&nbsp;为什么需要&nbsp;ArrayList&nbsp;而不是直接使用数组?58.&nbsp;数组和链表在&nbsp;Java&nbsp;中的区别是什么?59.&nbsp;ArrayList&nbsp;的扩容机制是怎样的?60.&nbsp;ArrayList&nbsp;的缺点有哪些?如何使其线程安全?61.&nbsp;如何使一个集合不可修改?62.&nbsp;使用&nbsp;HashMap&nbsp;时有哪些提升性能的技巧?63.&nbsp;什么是哈希碰撞?在&nbsp;HashMap&nbsp;中如何解决哈希碰撞?64.&nbsp;HashMap&nbsp;的&nbsp;put&nbsp;方法执行流程是怎样的?65.&nbsp;为什么&nbsp;HashMap&nbsp;在扩容时总是以&nbsp;2&nbsp;的&nbsp;n&nbsp;次方倍增长?66.&nbsp;ConcurrentHashMap&nbsp;在&nbsp;get&nbsp;方法中是否需要加锁?67.&nbsp;为什么&nbsp;HashMap&nbsp;不支持&nbsp;key&nbsp;或&nbsp;value&nbsp;为&nbsp;null?68.&nbsp;Java&nbsp;中如何创建多线程?69.&nbsp;线程池的工作原理是什么?70.&nbsp;Java&nbsp;中的线程是如何进行通信的?71.&nbsp;join&nbsp;方法的原理是什么?72.&nbsp;主线程如何知道子线程创建成功?73.&nbsp;反射的原理是什么?74.&nbsp;Java&nbsp;内存模型是什么?如何保证可见性和有序性?75.&nbsp;final&nbsp;关键字是否能够保证变量的可见性?
点赞 评论 收藏
分享
评论
2
11
分享

创作者周榜

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