【问题标题】:Value gets overwritten in Runnable class - Java值在 Runnable 类中被覆盖 - Java
【发布时间】:2017-10-06 14:06:52
【问题描述】:

我遇到了 Runnable 类的问题。当相同的值传递给另一个类时,传递给可运行类的值将被它收到的最后一个值覆盖。 可运行类的功能是将值传递给另一个类中的另一个函数以打印它们。但只打印 Runnable 类收到的最后一个值。

这是我的代码, 这是传递值的主类。

public class MainClass {
    private int intVal = -1;
    public void MainMethod() {
        ExecutorUtil theExecutor = ExecutorUtil.GetInstance();
        for(int i = 0; i < 3; i++) {
            intVal = i;
            synchronized (this) {
                theExecutor.SubmitTask(new ActionExecutor(intVal));
            }
        }
    }
}

这是我用来调用线程的 executorUtil。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.BlockingQueue;

public class ExecutorUtil {
    private static ExecutorUtil theInstance;
    private ExecutorService theExecutor;
    private BlockingQueue<Runnable> theQueue;



    protected ExecutorUtil() {
        theExecutor = CreateThreadPoolExecutor();
    }

    private ExecutorService CreateThreadPoolExecutor() {
        theQueue = new LinkedBlockingQueue<Runnable>();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 900, java.util.concurrent.TimeUnit.SECONDS, theQueue);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        return threadPoolExecutor;
    }

    public static ExecutorUtil GetInstance() {
        if (theInstance == null) {
            synchronized(ExecutorUtil.class) {
                if (theInstance == null) {
                    theInstance = new ExecutorUtil();
                }
            }
        }
        return theInstance;
    }

    public void SubmitTask(Runnable runnable) {
        theExecutor.submit(runnable);
    }
}

这是将接收到的值传递给打印这些值的函数的线程。

public class ActionExecutor implements Runnable {
    int iVal = -1;
    public ActionExecutor(int iVal) {
        this.iVal = iVal;
    }
    public void run() {
        SecondClass sc = new SecondClass();
        sc.printIntVal(iVal);
    }
}

这是打印值的类。

public class SecondClass {
    public void printIntVal(int i) {
        System.out.println(i);
    }
}

预期输出:

0
1
2

获得的输出:

2
2
2

不知道为什么会这样!

更新:

仅当使用非原始数据类型时才会出现此问题。在我的示例中,我使用了一个整数值 (intVal)。由于 java 传递原始数据类型的值,因此按预期获得了输出。但在我的原始代码中,我使用了 JSONObject。并且由于 java 为非原始数据类型传递对象的引用,因此该值被覆盖。

我通过为每次迭代创建新的 JSONObject 解决了这个问题。

【问题讨论】:

  • 一般来说,你的代码包含很多不正确的多线程解决方案,会导致各种微妙的难以解决的情况。除此之外,您使用的代码约定与 Java 开发中的标准相去甚远,导致代码难以阅读。
  • 其实这不是原始代码。我把原代码简化了,方便其他SO用户理解我的问题!

标签: java multithreading executorservice


【解决方案1】:

似乎在某处您有 static 字段,用于存储您的号码。 所以,我想,你有 3 个 ActionExecutor 实例,但看起来 field 有 static 修饰符,所以每个实例都有最新的值。

检查这个案例...

【讨论】:

  • 不,我没有任何静态字段。
  • 调用 sc.printIntVal() 之前在 ActionExecutor 中打印的值是 0、1 和 2。但在 SecondClass 内部它们打印为 2、2 和 2
【解决方案2】:

所以在我阅读了您的问题并研究了您的代码之后,我不妨尝试一下。你瞧,它按预期工作。这里唯一的区别是存在竞争条件,因此输出顺序不同,但不会打印相同的数字。 输出可能

  • 第一:0 1 2
  • 第二:0 1 2
  • 第三:2 1 0

这里是完整的代码来试一试:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

public class MainClass {

     private int intVal = -1;
        public void MainMethod() {
            ExecutorUtil theExecutor = ExecutorUtil.GetInstance();
            for(int i = 0; i < 3; i++) {
                intVal = i;
                synchronized (this) {
                    theExecutor.SubmitTask(new ActionExecutor(intVal));
                }
            }
        }

        public class ActionExecutor implements Runnable {
            int iVal = -1;
            public ActionExecutor(int iVal) {
                this.iVal = iVal;
            }
            public void run() {
                SecondClass sc = new SecondClass();
                sc.printIntVal(iVal);
            }
        }
        public class SecondClass {
            public void printIntVal(int i) {
                System.out.println(i);
            }
        }

        public static class ExecutorUtil {
          private static ExecutorUtil theInstance;
            private ExecutorService theExecutor;
            private BlockingQueue<Runnable> theQueue;



            protected ExecutorUtil() {
                theExecutor = CreateThreadPoolExecutor();
            }

            private ExecutorService CreateThreadPoolExecutor() {
                theQueue = new LinkedBlockingQueue<Runnable>();
                ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 900, java.util.concurrent.TimeUnit.SECONDS, theQueue);
                threadPoolExecutor.allowCoreThreadTimeOut(true);
                return threadPoolExecutor;
            }

            public static ExecutorUtil GetInstance() {
                if (theInstance == null) {
                    synchronized(ExecutorUtil.class) {
                        if (theInstance == null) {
                            theInstance = new ExecutorUtil();
                        }
                    }
                }
                return theInstance;
            }

            public void SubmitTask(Runnable runnable) {
                theExecutor.submit(runnable);
            }
        }

        public static void main(String[] args) {
            MainClass main = new MainClass();
            main.MainMethod();
        }
}

您可能想要清理并重建您的项目。否则它正在工作..

【讨论】:

  • 清理并重建。但还是同样的问题!
  • @DeepikaMasilamani 无论您在代码中简化 什么,这个都可以工作。不知道你的实际代码是什么样子的..
  • 我更新了我的帖子。非原始数据类型会出现此问题。由于 java 对非原始数据类型使用“引用调用”,因此该值被覆盖。很抱歉没有在帖子中提及原始数据类型。
猜你喜欢
  • 1970-01-01
  • 2014-07-23
  • 2016-12-27
  • 2013-09-02
  • 2012-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多