加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 实现线程安全共享计数器的功能方法

发布时间:2020-12-15 00:04:45 所属栏目:Java 来源:网络整理
导读:我对 Scala和函数式编程比较陌生,我喜欢使用不可变对象的想法,我可以避免许多线程安全陷阱.有一件事仍然困扰着我,这是用于教授线程安全的经典示例 – 共享计数器. 我想知道是否可以实现线程安全计数器(在此示例中为请求计数器),使用不可变对象和功能概念,并
我对 Scala和函数式编程比较陌生,我喜欢使用不可变对象的想法,我可以避免许多线程安全陷阱.有一件事仍然困扰着我,这是用于教授线程安全的经典示例 – 共享计数器.

我想知道是否可以实现线程安全计数器(在此示例中为请求计数器),使用不可变对象和功能概念,并完全避免同步.

所以在这里参考首先是计数器的经典可变版本
(请原谅我的公共成员变量,仅为了简洁示例)

可变,非线程安全版本:

public class Servlet extends HttpServlet {

  public int requestCount = 0; 

  @Override
  public void service(ServletRequest req,ServletResponse res) throws ... {
    requestCount++; //thread unsafe
    super.service(req,res);  
  }
}

可变,经典的线程安全版本:(或者我希望…)

public class Servlet extends HttpServlet {

  public volatile int requestCount = 0;

  @Override
  public void service(ServletRequest req,ServletResponse res) throws ... {
    synchronized (this) {
      requestCount++;
    }
    super.service(req,res);  
  }
}

我想知道是否有一种方法使用不可变对象和volatile变量来实现线程安全而不需要同步.

所以这是我天真的尝试.我们的想法是为计数器提供一个不可变对象,并使用volatile变量替换对它的引用.感觉很腥,但值得一试.

持有人:

public class Incrementer {
  private final int value;
  public Incrementer(final int oldValue) {
    this.value = oldValue + 1;
  }

  public Incrementer() {
    this.value = 0;
  }

  public int getValue() {
    return value;
  }
}

修改后的servlet:

public class Servlet extends HttpServlet {

  public volatile Incrementer incrementer = new Incrementer();

  @Override
  public void service(ServletRequest req,ServletResponse res) throws ... {
    incrementer = new Incrementer(incrementer.getValue());
    super.service(req,res);
  }
}

我有一种强烈的感觉,这也不是线程安全的,因为我从增量器读取,并且可能得到一个陈旧的值(例如,如果引用已经被另一个线程替换).如果它确实不是线程安全的,那么我想知道是否存在任何“功能”方式来处理这种没有锁定/同步的计数器场景.

所以我的问题是

>这个线程是否安全?
>如果是,为什么?
>如果没有,是否有任何方法可以在没有同步的情况下实现这样的计数器?

虽然上面的示例代码是用Java编写的,但Scala中的回复当然也是受欢迎的

解决方法

Is this thread safe by any chance?

不,除非您已在同步块中创建了不可变对象,否则这不是线程安全的.在线程竞争条件下有可能创建一个损坏的不可变对象.

要实现相同的功能,您可以使用AtomicInteger,避免显式同步.

public class Servlet extends HttpServlet {

  public AtomicInteger incrementer = new AtomicInteger (0);

  @Override
  public void service(ServletRequest req,ServletResponse res) throws ... {
    int newValue = incrementer.incrementAndGet();
    super.service(req,res);
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读