zoukankan      html  css  js  c++  java
  • Java带参数的线程类ParameterizedThread——即如何给Thread传递参数

    在Java中似乎没有提供带运行参数的线程实现类,在第三方类库中也没有找到。网上有大量的文章在讨论这个问题,但都没有提供很好的代码封装解决方案,这令我很吃惊。如果读者知道有官方或者第三方的实现方式,欢迎留言说明。本文最后给出了一种实现带运行参数的线程实现类。

    C#的基础类库中早就提供了相关的解决方案,如下是C#几种常见的带参数子线程创建方法:

    Thread th = new Thread((param) =>
    {
         Console.WriteLine(param);
    });
    th.Start(i);
    
    Task.Factory.StartNew((param) =>
    {
         Console.WriteLine(param);
    }, i);
    
    ThreadPool.QueueUserWorkItem((param) =>
     {
         Console.WriteLine(param);
    }, i);

    我们从一个实际编码问题开始讲起,主线程循环一个集合元素,并创建子线程中做相应的处理(可能比较耗时)。下面是最初的一段实现代码,请问这段代码存在什么问题?

    for (int i = 0; i < 100; i++) {
        Thread th = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(i + "");
            }
        });
        th.start();
    }

      (1)首先这段程序是无法通过编译的,在intellij idea中提示“Variable 'i' is accessed from within inner class,needs to be final or effectively final”,在Eclipse中提示"Local variable i defined in an enclosing scope must be final or effectively final",意思是说在内部类中无法访问外部类中不是final修饰的成员变量。那么我们很容易想通过下面的方式解决:

    for (int i = 0; i < 100; i++) {
        int p = i;
        Thread th = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(p + "");
            }
        });
        th.start();
    }

     这段代码能够通过编译,而且似乎运行良好。但是不是线程安全的,父线程中的循环变量不断被修改,子线程得到的父线程成员变量可能是不正确的。

    (2)其次上面的代码在循环体内创建了大量的子线程,线程的创建和销毁会造成系统资源的开销,一般推荐使用线程池的方式创建线程,比如ThreadPoolExecutor。

    ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
            
    for (int i = 0; i < 100; i++) {
        int p=i;
        executor.execute(()->{
            System.out.println(p + "");
        });
    }

    那么有什么办法使得子线程能够安全的获取到父线程的变量呢,我们可以编写如下的线程实现类:

    public class MyRunnable implements Runnable {
    
        Object param;
    
        public MyRunnable(Object parameter) {
            this.param = parameter;
        }
    
        @Override
        public void run() {
            System.out.println(param.toString());
        }
    }

    这里的问题是我们必须针对不同的情形,编写不同的子线程实现类,在各个工程中分散了很多类似的脚手架代码,闻到这种“味道”,我们应该想到需要进行代码抽象和封装,以便于重复使用。据此,笔者用Java封装了一个带参数的线程类:

    /**
     * ParameterizedThreadStart defines the start method for starting a thread.
     * @author wadexmy
     * @param <T>
     */
    public interface ParameterizedThreadStart<T>{
        /**
         * a method with parameter
         * @param context
         */
        void run(T context);
    }
    /**
     * ParameterizedThread defines a thread with a generic parameter
     * @author wadexmy
     * @param <T>
     */
    public class ParameterizedThread<T> implements Runnable{
    
        private T context;
        private ParameterizedThreadStart<T> parameterStart;
    
        /**
         * Constructor
         * @param context
         */
        public ParameterizedThread(T context,ParameterizedThreadStart<T> parameterStart){
            this.context=context;
            this.parameterStart=parameterStart;
        }
    
        /**
         * getContext returns the context of current thread.
         * @return
         */
        public T getContext(){
            return context;
        }
    
        /**
         * run method to be called in that separately executing thread.
         */
        @Override
        public void run() {
            parameterStart.run(context);
        }
    }

    类ParameterizedThread实现了 Runnable,在构造方法中传递了一个参数和需要执行的方法。可以通过下面的代码测试这个类:

    ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    for (int i = 0; i < 100; i++) {
        executor.execute(new ParameterizedThread<>(i, (p) -> {
            System.out.println(p.toString());
        }));
    }
  • 相关阅读:
    [Nowcoder] 寻找子串
    [LeetCode] Generate Parentheses
    [Nowcoder] 字符串是否由字串拼接
    ananconda3中QTDesigner无法输入中文
    [Paddle学习笔记][13][基于YOLOv3的昆虫检测-测试模型]
    [Paddle学习笔记][12][基于YOLOv3的昆虫检测-模型预测]
    [Paddle学习笔记][11][基于YOLOv3的昆虫检测-训练模型]
    [Paddle学习笔记][10][基于YOLOv3的昆虫检测-损失函数]
    [Paddle学习笔记][09][基于YOLOv3的昆虫检测-模型设计]
    [Paddle学习笔记][08][基于YOLOv3的昆虫检测-数据处理]
  • 原文地址:https://www.cnblogs.com/wangnmhb/p/9226550.html
Copyright © 2011-2022 走看看