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线程池、如何停止一个线程

  • 相关阅读:
    2020-03-1811:29:37springboot与任务
    2020-03-17 20:18:50springboot整合rabbitmq
    2020.03.17 springboot缓存相关
    前端JS面试
    npm 常用指令
    ES8新特性
    ES7新特性
    ES6新特性
    SpringBoot
    SpringBoot
  • 原文地址:https://www.cnblogs.com/theRhyme/p/11369069.html
Copyright © 2011-2022 走看看