【问题标题】:Java - multithreading incrementJava - 多线程增量
【发布时间】:2015-06-03 03:44:05
【问题描述】:

我的应用程序中有以下课程

public class InsertErrorLinesHandler {

    private int currentCount;

    public void insertErrorLine() {
        //do something...
        currentCount++;
    }
}

我有多个线程使用InsertErrorLinesHandler 的同一实例,特别是调用 insertErrorLine 方法。在所有这些线程都停止后,我从这个实例中得到了currentCount

问题是——如何重写这个类以确保不会有任何并发​​问题?我想要确定的是,currentCount 值将是来自线程的方法调用的计数。我应该使用静态方法和静态变量吗?使方法同步?使变量易变?

谢谢!

【问题讨论】:

    标签: java multithreading concurrency synchronization


    【解决方案1】:

    我建议使用AtomicInteger,它有一个线程安全的递增方法

    【讨论】:

    • Brian Goetz 的“Java 并发实践”一书专门解决了保持可从多个线程访问的计数器的问题。他的解决方案是使用AtomicLong。简单有效。
    【解决方案2】:

    简单修复,使方法调用同步:

    public class InsertErrorLinesHandler {
    
        private int currentCount;
    
        public void synchronized insertErrorLine() {
            //do something...
            currentCount++;
        }
    }
    

    【讨论】:

    • 我很想这样做,但是有疑问,也许有更好的方法...
    • 最好的方法通常是最简单的。其他方法将涉及拥有一个用于同步增量操作的静态对象,导入多个类,甚至重写类。明智地选择
    • 简单,是的;但是如果//do something... 花费大量时间并且不影响其他线程,则效率非常低。不太简单但更优化的方法是在 currentCount++ 语句周围包裹一个 synchronized 块。
    • 很高兴看到您的简单修复包含一个巨大的错误。如果不将该字段标记为 volatile,其他线程可能无法看到更改。单独同步并不能保证多线程的安全。
    • @NicoVanBelle,我明白你关于让它变得易变的观点,但这是否意味着在线程进入同步块并执行currentCount++ 之后,currentCount 的实际值有可能不会被写入内存?
    【解决方案3】:

    使用AtomicInteger 或在线程数更多时使用LongAdder 以获得更好的性能。

    这是关于如何使用 AtomicInteger 的示例,

    public class InsertErrorLinesHandler {
       AtomicInteger counter = new AtomicInteger();
    
       public void insertErrorLine() {
           counter.incrementAndGet();
       }
    
       public int get() {
           return counter.get();
       }
    }
    

    【讨论】:

      【解决方案4】:

      到目前为止,没有人解决您的这部分问题:

      我应该使用静态...?

      是否使用static的选择完全独立于是否使用synchronizedAtomicInteger的选择。答案取决于您要计算的内容。

      Java 中的static 字段是一些其他语言所称的全局 变量:整个程序只有一个。一个非静态字段(也称为实例变量)存在于多个副本中——一个对应于它所属的类的每个实例。

      您的程序创建了多少InsertErrorLineHandler 类的实例?如果不止一个,那么您希望每个实例都有自己的counter,还是希望所有实例共享相同的counter?声明字段 static 意味着它们都将共享相同的字段,而省略 static 关键字意味着每个实例都有自己的计数器。

      如果您的程序只创建了一个 InsertErrorLineHandler 实例(即,如果您将其用作 singleton 类),那么您不应使用 static。将字段设置为 static 或非静态不会改变单例的行为,但在单例中使用 static 会是不好的风格。

      【讨论】:

      • 只有一个 InsertErrorLineHandler 实例。所以我觉得我没用static是对的
      猜你喜欢
      • 2010-10-30
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-07
      相关资源
      最近更新 更多