zoukankan      html  css  js  c++  java
  • 多个线程分别顺序交替打印一种不同字符abcdefg(已实现随便多少个线程打印多少个字符,利用线程池实现多线程)

    下面实现多线程顺序打印字符"abcdefg";

    实现Runnable接口:

    /**
     * @author: rhyme
     * @date: 2019-08-17 14:39
     * @topic: "Runnable"
     * @description: "每个线程通过sign表示需要打印的字符数组下标,index表示将要打印的字符数组的下标"
     */
    public class PrintRunnable implements Runnable {
    
        private final char[] chars;
        /**
         * 当前线程只能打印的那个字符对应数组的下标
         */
        private final int sign;
        /**
         * 当前将要打印的字符数组下标
         */
        private volatile static int index;
    
        private final static Class<PrintRunnable> CLASS_LOCK = PrintRunnable.class;
    
        public PrintRunnable(String chars, int sign) {
            this.chars = chars.toCharArray();
            this.sign = sign;
        }
    
        @Override
        public void run() {
            try {
                while (true) {
                    // 为了结合线程池shutdownNow方法设置中断interrupt停止线程
                    /*if (Thread.currentThread().isInterrupted()) {
                        break;
                    }*/
    
                    synchronized (CLASS_LOCK) {
                        if (index % chars.length == sign) {
                            System.out.printf("ThreadName : %s is printing (%c)
    ", Thread.currentThread().getName(), chars[sign]);
                            index++;
                            CLASS_LOCK.notifyAll();
                        }
    
                        CLASS_LOCK.wait();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.err.printf("ThreadName : %s InterruptedException
    ", Thread.currentThread().getName());
            }
        }
    }

    这里实现Runnable接口,两个重要的属性sign和index;

    sign表示当前线程打印的那个字符在字符数组中的下标

    index表示移动字符下标打印, index % chars.length(重要,顺序打印的核心实现)的值表示需要打印的字符的下标,当一个字符被打印,index++;

    chars表示一个字符数组;

    wait()这里有两个作用,一个是为了让当前线程等待不马上循环获取锁影响效率,另一个可以通过设置线程中断interrupt抛异常停止;

    notifyAll唤醒所有对应锁wait()的线程;

    这里也可以不用wait和notifyAll,那每个线程就不会wait,重复循环获取锁占用资源影响效率,其次可判断线程是否被设为中断,则break退出循环。

    利用线程池启动:

    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    
    import java.util.concurrent.*;
    
    /**
     * @author: rhyme
     * @date: 2019-08-17 14:37
     * @topic: "多个线程打印"
     * @description: "多个线程有序打印abcdefg"
     */
    public class MultiThreadPrintOrder {
        public static void main(String[] args) throws InterruptedException {
            final String string = "abcdefg";
    
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                    .setNameFormat("order-pool-%d")
                    .build();
    
            ExecutorService threadPoolExecutor =
                    new ThreadPoolExecutor(
                            string.length(),
                            string.length(),
                            0L,
                            TimeUnit.SECONDS,
                            new ArrayBlockingQueue<>(1),
                            namedThreadFactory,
                            new ThreadPoolExecutor.AbortPolicy());
    
            for (int i = 0; i < string.length(); i++) {
                threadPoolExecutor.execute(new PrintRunnable(string, i));
            }
    
            // 3秒后线程池调用shutdownNow设置线程中的interrupt中断标志位
            TimeUnit.SECONDS.sleep(3);
            System.out.printf("ThreadName: (%s) Preparing call shutdownNow()...
    ", Thread.currentThread().getName());
            threadPoolExecutor.shutdownNow();
    
        }
    }

    这里通过guava包中ThreadFactoryBuilder设置线程池中的线程名

    提交string.length()个不同的线程任务(通过下标i打印不同的字符)到线程池中;

    3秒后,主线程调用shutdownNow,这里主要是为了将正在运行的线程设置中断标志位,死循环利用中断标志位结束循环,或线程调用了等待方法(如wait)会抛出异常InterruptException未被捕获而停止

    shutdownNow 方法:此方法执行后不得向线程池再提交任务,如果有空闲线程则销毁空闲线程,取消所有位于阻塞队列中的任务,并将其放入 List容器,作为返回值;取消正在执行的线程(实际上仅仅是设置正在执行线程的中断标志位,调用线程的 interrupt 方法来中断线程)。

    启动main方法,多个线程按顺序打印"abcdefg",3s后结束,执行结果部分截图如下:

     当然也可以通过另一种"等待-唤醒"机制实现,如用一个ReentrantLock对象的的newCondition()方法创建多个Condition对象,再利用Condition对象的await()搭配signal()signalAll()

    也可利用取余运算%判断线程需要打印的字符,不用生成多个 Condition对象,可利用一个Condition对象,而且可以改变,随便多少个线程打印多少个字符。

    JAVA线程状态、线程START方法源码、多线程、JAVA线程池、如何停止一个线程

  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/theRhyme/p/11369069.html
Copyright © 2011-2022 走看看