线程安全的统计工具(计数器)

利用Java中的AtomicInteger实现高并发环境下的线程安全计数器 AtomicInteger`是Java并发包中一个非常实用的工具类,它通过硬件级别的CAS指令,为开发者提供了一种高效、线程安全的整数更新方案。在实现高并发计数器这类需求时,它往往是优于传统同步锁的首选。然而,开发者也需要清楚其适用场景和潜在限制,对于更复杂的并发控制,可能需要结合使用`ConcurrentHashMap`、`LongAdder`(适用于高并发写多读少的求和场景)等其他并发组件来构建健壮的高性能应用。 阅读详情

问题描述

    我们需要一个统计工具来统计诸如查询次数,最短和最长的查询时间,另外还需要按类别来统计,比如按城市统计查询数量等等。

    我们需要它是线程安全的,因为我们会有很多线程同时更新统计数据。

简单的方案

    最简单的方案是不保证线程安全,因为既然是统计数据,那么差一点点也许没有问题。

    其次比较简单的翻案就是用synchronized保护所有的数据,这是首先推荐的做法,如果发现有性能问题,再看下面更加复杂的方案。

高效但复杂的方案

    我们这里就假设需要非常高效并且线程安全的方案(比如需要追求极致性能或者你是性能优化狂)。

 

问题1 统计查询次数 

    这个比较简单,使用AtomicInteger或者AtomicLong就可以了。比如:

      privatefinal AtomicLong totalQuery=new AtomicLong();

        public void addTotalQuery(){

            totalQuery.incrementAndGet();

      }


 

问题2 统计最短查询时间

     首先看不做任何同步会怎么样?

       private long minTime=Long.MAX_VALUE;

       public void updateMinTime(long time){

           if(time<minTime){

                minTime=time;

           }

       }

       public long getMinTime(){

           return minTime;

       }


 

     比如minTime的当前值是5,然后线程1的time是3,线程2的time是4,他们同时发现自己比5小,所以都会试图把自己的值赋给minTime。

     如果线程1先赋值,线程2后赋值,那么最终的值将是4,这样就记错了。

     除了上面的问题,这个方法还有个bug,JVM对long的赋值不是原子的,尤其是对于32位的JVM,很可能一个long的赋值先修改高32位,然后修改低32位,那么如果

     在这直接有人读取这个值,那么就会读到奇怪的结果。

     另外即使没有人读,两个线程同时写一个long也会出现一个线程更新了高32位,另一个修改了低32位的情况。解决原子修改的问题可以使用volatile或者AtomicLong都可以,但是即使改成了volatile或者AtomicLong,仍然不能解决第一个带来的race condition。

     那么怎么解决呢?当然加锁是一种方案

       @Guarded by this
       private long minTime=Long.MAX_VALUE;
       public void synchronized updateMinTime(long time){
           if(time<minTime){
                minTime=time;
           }
       }
       public void synchronized getMinTime(){
           return minTime;
       }

     注意:不但更新需要synchronized,读取也需要synchronized。因为synchronized除了互斥的语义之外,还定义了happens-before的关系,它保证updateMinTime的结果完成后才会执行getMinTime,而且和volatile一样,它保证了可见性。

    我们可以用volatile或者AtomicLong稍微优化一下:


       @Guarded by this
       private volatile long minTime=Long.MAX_VALUE;
       public void synchronized updateMinTime(long time){
           if(time<minTime){
                minTime=time;
           }
       }
       public void getMinTime(){
           return minTime;
       }

      我们用synchronized来保证只有一个线程能够修改minTime,而且由于它是volatile的,所以getMinTime不会读到更新long一半的情况。

      但这样只能有一个线程修改minTime,还是不是特别高效。

      我们能够发现:其实大部分线程的值都不是最小的值,它发现自己的值可能比minTime大,那么根本不需要更新。那能不能下面这样优化呢?

       @Guarded by this
       private volatile long minTime=Long.MAX_VALUE;
       public void updateMinTime(long time){
           if(time<minTime){             
               synchronized(this){
                   minTime=time;
               }
           }
       }
       public void getMinTime(){
           return minTime;
       }

       还是不行,因为还是可能线程1和线程2同时发现自己比较小,然后都试图更新,依然会出现上面的问题。

        当然如果大家碰到过Lazy Initialization的问题可能会知道可以使用类似Double Check Lock的方法来优化。

       @Guarded by this
       private volatile long minTime=Long.MAX_VALUE;
       public void updateMinTime(long time){
           if(time<minTime){
               synchronized(this){
                  if(time<minTime){//check again
                       minTime=time;
                  }
               }
           }
       }
       public void getMinTime(){
           return minTime;
       }

          这种使用double check lock的方法配合volatile的方案是没有问题的。但是明显实现起来很复杂。

          我们再来仔细分析它为什么正确。

          如果线程1和线程2同时发现自己比当前的minTime小,那么只有一个线程能进入synchronized代码段,这个时候再检查一下自己的值是否小于当前值。

          如果当前值比自己小,那么说明在第一次判断和拿到锁这段时间内有别人修改了最小值,而且还比自己小,那么自己就没有比更新最小值了。

          否则自己还是最小值,而且由于已经拿到锁,所以不会再有人能修改最小值,所以可以放心的更新最小值。

          它比在外层加锁的好处是:大部分时候第一个if就发现自己不是最小值了,那么更本不需要加锁,所以很快。

           我们总结一下它正确的原因:那就是它保证了条件判断(if(time<minTime))和修改(minTime=time;)是原子的,这个是通过synchronized来实现的。

           除了synchronized之外,很多现代处理器都提供了一些原子的指令,比如CAS。我们可以使用这些原子的指令来实现同样的功能。

           当然Java是跨平台的实现,它会考虑各种处理器,如果能够使用CAS,那么它会尽量使用,如果不能,那么使用操作系统或者其它的库来实现语义上的原子操作。

           这里我们可以使用AtomicLong.compareAndSet。

	private final AtomicLong minTime=new AtomicLong(Long.MAX_VALUE);
        public void updateMinTime(long sample){
	    while (true) {
	        long curMin = minTime.get();
	        if (curMin > sample) {
	            boolean result = minTime.compareAndSet(curMin, sample);
	            if (result) break;
	        } else {
	            break;
	        }
	    }
	}

           我们仔细看一下它的实现。

           它在一个"死循环"里面,首先拿到“当前”的最小值,如果自己比“当前”的最小值大了,那么就不需要更新了,直接break退出。

           如果自己比较小,那么就尝试  boolean result = minTime.compareAndSet(curMin, sample);

           compareAndSet尝试把minTime更新为sample,前提是minTime的值是curMin。可以这样理解这条语句:

    synchronized(this){
        if(minTime==curMin){
             minTime=sample;
             return true;
        }
        return false;
     }

          当然这是语义上的等价,实际上它很可能只是一条机器指令。

           也就是说,我先读取“当前”最小值,然后加锁,然后判断此刻的最小值是否是前面“当前“最小值,如果是,那么说明我还是最小的值(因为我已经加锁,没人能修改)。我可以放心的更新

           如果此刻的最小值不等于前面读过的最小值,那么说明这之间有人修改过了,那么我修改就可能失败(也有可能成功),那么我需要重试。

           使用CAS的优点是:如果竞争不是很激烈,那么性能非常高。因为这是一种“乐观”锁,它不停的尝试获取锁(其实就是CAS),再多线程都不会导致对方等待(当然如果一直不能CAS成功就是在忙等待)。

           当然缺点就是:如果竞争非常激烈,会让很多CPU时间都在CAS上,我们完全可以“阻塞”当前线程,让cpu干点别的。

问题3 按类别统计次数(线程安全的Map)

           比如我们需要按城市来统计查询。那么最容易想到的自然是ConcurrentHashMap<String,Long>。但是同样更新次数时有同步的问题,所以我们可以使用AtomicLong

    private final ConcurrentHashMap<String, AtomicLong> map=new ConcurrentHashMap<String, AtomicLong>();
    public void addCount(String key,long value){
        AtomicLong counter=map.get(key);
        if(counter==null){
            counter=new AtomicLong();
            map.put(key,counter);
        }
        counter.addAndGet(value);
    }

          上面的代码是有问题的,和前面一样,有可能有两个线程同时发现counter为空,同时new了一个AtomicLong,后new的线程会导致前面的值没有累计进去。

           当然我们可以采样类似的方法来double check

    private final ConcurrentHashMap<String, AtomicLong> map=new ConcurrentHashMap<String, AtomicLong>();
    public void addCount(String key,long value){
        AtomicLong counter=map.get(key);
        if(counter==null){
            synchronized(this){
                if(counter==null){ //check again
                    counter=new AtomicLong();
                    map.put(key,counter);
                }
            }
        }
        counter.addAndGet(value);
    }

            同样,我们也可以采样类似CAS的指令------putIfAbsent来实现block free的算法。这种算法在竞争不是非常激烈时很高效,它不会导致线程阻塞而带来切换。

	public void addCounter(String key, long count){
		if(count<=0) return;
		AtomicLong current = map.get(key);
                if(current == null) {
                    AtomicLong al=new AtomicLong();
                    current=map.putIfAbsent(key, al);
        	    if(current == null) current=al;
                }

                assert current!=null;
                current.addAndGet(count);

	}

            putIfAbsent会尝试放入新的key和value,它首先检查这个key是否存在,如果存在,返回老的value,否则插入新的k-v对,并返回老的value。

            如果返回值是null,说明我这个线程更新成功了,那么current就直接使用我构造的al,否则说明别人更新成功,我直接拿到了别人值。

            细心的同学可能有这样的疑问:和Double Check Lock一样,会不会由于编译器或者cpu的reordering导致AtomicLong al=new AtomicLong();没有完全构造好,而其它线程拿到它呢?

            我也有过这样的疑问,同时发现guava的实现和我上面的实现有类似的问题(https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/util/concurrent/AtomicLongMap.java?name=v11.0-rc1)

            后来询问了一下,是没有问题的,在 ConcurrentMap 的文档里明确写了:Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a ConcurrentMap as a key or value happen-before actions subsequent to the access or removal of that object from the ConcurrentMap in another thread.

            有兴趣的同学可以看看后面参考文献和邮件通信。

参考资料

1. http://stackoverflow.com/questions/6072040/thread-safe-implementation-of-max

2. http://stackoverflow.com/questions/8477352/global-in-memory-counter-that-is-thread-safe-and-flushes-to-mysql-every-x-increm

3. http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/AtomicLongMap.html

4. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentMap.html

5. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html#putIfAbsent%28K,%20V%29

6. https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/util/concurrent/AtomicLongMap.java?name=v11.0-rc1

7. http://www.cs.umd.edu/%7Epugh/java/memoryModel/DoubleCheckedLocking.html

 

[guava] is my counter thread safe and my question about AtomicLongMap?

   Inbox 
Add star 

LiLi

<fancyerii@gmail.com>
Fri, Jun 29, 2012 at 6:46 PM
To: guava-discuss@googlegroups.com
hi all
  I have read http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
and know a little about Java memory model.
  I want to implement a thread safe and efficient Map<String,int>
counter. I found a related question in stackoverflow
http://stackoverflow.com/questions/8477352/global-in-memory-counter-that-is-thread-safe-and-flushes-to-mysql-every-x-increm
  my implementation is :

       private ConcurrentHashMap<String, AtomicLong> counter=new
ConcurrentHashMap<String, AtomicLong>();

       public void addCount(String key, long count){
               if(count<=0) return;
               AtomicLong current = counter.get(key);
               if(current == null) {
                   current=counter.putIfAbsent(
key, new AtomicLong());
                   if(current == null) current=counter.get(key);
               }

               assert current!=null;
               current.addAndGet(count);

       }
  but after I reading
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
. it seems there exists a state that may fail.
  if thread1 call addCount("key",2); and thread2 call
addCount("key",1); at the same time.
  thread1 executes AtomicLong current = counter.get(key);  and gets null.
  then thread 1 execute
         if(current == null) {
                   current=counter.putIfAbsent( k ey, new AtomicLong());
  as compilers/cpus may disorder, new AtomicLong() will not be null
but may be well constructed.
  Then thread 2 call AtomicLong current = counter.get(key); it's not
null but not well constructed. then it call current.addAndGet().
   Will thread 2 crash if current is not well constructed?

   I also find similar implementation in a popular lib -- guava
https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/util/concurrent/AtomicLongMap.java?name=v11.0-rc1
   it may also fail like my codes.
   e.g. thread 1 call atomic = map.putIfAbsent(key, new AtomicLong(delta));
          thread 2 get a not null atomic and call it's get();

public long addAndGet(K key, long delta) {
   outer: for (;;) {
     AtomicLong atomic = map.get(key);
     if (atomic == null) {
       atomic = map.putIfAbsent(key, new AtomicLong(delta));
       if (atomic == null) {
         return delta;
       }
       // atomic is now non-null; fall through
     }

     for (;;) {
       long oldValue = atomic.get();
       if (oldValue == 0L) {
         // don't compareAndSet a zero
         if (map.replace(key, atomic, new AtomicLong(delta))) {
           return delta;
         }
         // atomic replaced
         continue outer;
       }

       long newValue = oldValue + delta;
       if (atomic.compareAndSet( oldValue , newValue)) {
         return newValue;
       }
       // value changed
     }
   }
 }

--
guava-discuss@googlegroups.com
Project site: http://guava-libraries.googlecode.com
This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.
To report an issue: http://code.google.com/p/guava-libraries/issues/entry
To get help: http://stackoverflow.com/questions/ask (use the tag "guava")
Reply | Reply to all | Forward | Print | Delete | Show original

Add star 

tsuna

<tsunanet@gmail.com>
Sat, Jun 30, 2012 at 12:01 AM
To: LiLi <fancyerii@gmail.com>
Cc: guava-discuss@googlegroups.com
On Fri, Jun 29, 2012 at 3:46 AM, LiLi <fancyerii@gmail.com> wrote:
>    Will thread 2 crash if current is not well constructed?

No.  This issue won't arise with ConcurrentHashMap because:
  - Either the key is already in the map, in which case putIfAbsent
returns the existing entry;
  - Or the key is not already in the map, in which case putIfAbsent
_atomically_ inserts it in the map and returns null.

In the latter case, as documented by the contract of ConcurrentMap
( http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentMap.html)
"placing an object into a ConcurrentMap as a key or value
happen-before actions subsequent to the access".

In other words, because the code is guaranteed to be implemented in
such a way that there is a happen-before relationship between the call
to putIfAbsent in Thread 1, and the call to get in Thread 2.  So
Thread 2 will either see a correctly constructed AtomicLong, or it
will see null and will then race with thread 1 to insert the key in
putIfAbsent, which is perfectly fine as only one thread will
ultimately manage to create the key.

Put differently, it's as if the map was guaranteed to be implemented
with one lock per key, and that the lock was used to ensure that all
access to each entry in the map is done in a thread-safe manner.  Of
course in practice the implementation can be different, for example
ConcurrentHashMap is traditionally implemented by having multiple
internal hash maps, each of which is guarded by a single lock, and
that lock is only acquired on writes, whereas reads rely only on
volatile.  Guava's LoadingCache is implemented like that too (in fact
its code is actually a fork of that of ConcurrentHashMap).  There are
obviously many other implementations possible, most notable the one
used by NonBlockingHashMap, which is completely lock-free.

 

is my counter thread safe?

   Inbox 
Add star 

Li Li

<fancyerii@gmail.com>
Fri, Jun 29, 2012 at 6:41 PM
To: javamemorymodel-discussion@cs.umd.edu
hi all
   I have read http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
and know a little about Java memory model.
   I want to implement a thread safe and efficient Map<String,int>
counter. I found a related question in stackoverflow
http://stackoverflow.com/questions/8477352/global-in-memory-counter-that-is-thread-safe-and-flushes-to-mysql-every-x-increm
   my implementation is :

        private ConcurrentHashMap<String, AtomicLong> counter=new
ConcurrentHashMap<String, AtomicLong>();

        public void addCount(String key, long count){
                if(count<=0) return;
                AtomicLong current = counter.get(key);
                if(current == null) {
                    current=counter.putIfAbsent( key, new AtomicLong());
                    if(current == null) current=counter.get(key);
                }

                assert current!=null;
                current.addAndGet(count);

        }
   but after I reading
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
. it seems there exists a state that may fail.
   if thread1 call addCount("key",2); and thread2 call
addCount("key",1); at the same time.
   thread1 executes AtomicLong current = counter.get(key);  and gets null.
   then thread 1 execute
          if(current == null) {
                    current=counter.putIfAbsent( key, new AtomicLong());
   as compilers/cpus may disorder, new AtomicLong() will not be null
but may be well constructed.
   Then thread 2 call AtomicLong current = counter.get(key); it's not
null but not well constructed. then it call current.addAndGet().
    Will thread 2 crash if current is not well constructed?

    I also find similar implementation in a popular lib -- guava
https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/util/concurrent/AtomicLongMap.java?name=v11.0-rc1
    it may also fail like my codes.
    e.g. thread 1 call atomic = map.putIfAbsent(key, new AtomicLong(delta));
           thread 2 get a not null atomic and call it's get();

public long addAndGet(K key, long delta) {
    outer: for (;;) {
      AtomicLong atomic = map.get(key);
      if (atomic == null) {
        atomic = map.putIfAbsent(key, new AtomicLong(delta));
        if (atomic == null) {
          return delta;
        }
        // atomic is now non-null; fall through
      }

      for (;;) {
        long oldValue = atomic.get();
        if (oldValue == 0L) {
          // don't compareAndSet a zero
          if (map.replace(key, atomic, new AtomicLong(delta))) {
            return delta;
          }
          // atomic replaced
          continue outer;
        }

        long newValue = oldValue + delta;
        if (atomic.compareAndSet( oldValue, newValue)) {
          return newValue;
        }
        // value changed
      }
    }
  }
Reply | Reply to all | Forward | Print | Delete | Show original

Add star 

Pavel Rappo

<pavel.rappo@gmail.com>
Fri, Jun 29, 2012 at 6:54 PM
To: Li Li <fancyerii@gmail.com>
Cc: concurrency-interest <concurrency-interest@cs.oswego.edu>
Hi,

This 'counter.get(key)' cannot simply return "not well constructed"
object. The reason is that you use 'putIfAbsent' to put it in the map.
Either 'get' will return 'null' or it will return perfectly valid
AtomicLong object. There's a happen-before edge between these two
actions.
> ______________________________ _________________
> Javamemorymodel-discussion mailing list
> Javamemorymodel-discussion@cs.umd.edu
> https://mailman.cs.umd.edu/mailman/listinfo/javamemorymodel-discussion
>


--
Sincerely yours, Pavel Rappo.
Reply | Reply to all | Forward | Print | Delete | Show original

Add star 

Li Li

<fancyerii@gmail.com>
Fri, Jun 29, 2012 at 7:11 PM
To: Pavel Rappo <pavel.rappo@gmail.com>
do you mean my counter is safe?
putIfAbsent has a happen-before semantic? any document about this? Or
only current implementation guarantee this?

Add star 

Pavel Rappo

<pavel.rappo@gmail.com>
Fri, Jun 29, 2012 at 7:24 PM
To: Li Li <fancyerii@gmail.com>
Cc: concurrency-interest <concurrency-interest@cs.oswego.edu>
1. I can't see any obvious flaws in it.
2. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html
(see "Memory Consistency Properties")

Add star 

Li Li

<fancyerii@gmail.com>
Fri, Jun 29, 2012 at 7:30 PM
To: Pavel Rappo <pavel.rappo@gmail.com>

thanks.

在 2012-6-29 晚上7:24,"Pavel Rappo" < pavel.rappo@gmail.com>写道:

Add star 

Jeremy Manson

<jeremy.manson@gmail.com>
Mon, Jul 2, 2012 at 2:29 AM
To: Pavel Rappo <pavel.rappo@gmail.com>
Cc: Li Li <fancyerii@gmail.com>, concurrency-interest <concurrency-interest@cs.oswego.edu>
The counter field should be final, because another thread could read
the enclosing object before it is finished being constructed (unless
youve taken other precautions to prevent that.

Jeremy
> ______________________________ _________________
> Concurrency-interest mailing list
> Concurrency-interest@cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

 

java使用线程安全的单例模式实现网站计数器 四个java类 附上代码(比较简单)用于设计模式课程需要 登录类 package mytest.demo.WebCount; public class Login implements Runnable { // 登录名称 private String loginName; public String getLoginName() { return loginName; } public void setLoginName(String loginN 阅读详情

相关推荐

Flink累加器的应用:大数据处理

Flink累加器的应用:大数据处理Flink是一种流式处理框架,广泛应用于大数据处理和实时分析。在Flink中,累加器是一种重要的工具,用于在分布式环境中进行计数和聚合操作。本文将详细介绍Flink累加器的使用,并提供相应的源代码示例。一、什么是累加器? 在Flink中,累加器是一种特殊的变量,用于收集和聚合分布式任务的统计信息。累加器可以在不同任务之间共享和更新,从而实现全局的计数和聚合。它们通常用于收集诊断信息、计数特定事件的发生次数或跟踪任务的进度。二、累加器的类型 Flink提供了多种类型的累加器,

学习使你进步。 249

线程安全的计数器

不能通过编译的例子。 Creature creature = new Creature();是一个局部变量声明语句(local variable declaration statement) JLS 4.4,java语言规范不允许一个局部变量声明语句作为一条语句在循环中重复执行。一个本地变量声明作为一条只能直接出现在一个语句块中。(一个语句块又括号以及其中包括的语句和声明构成)  

业精于勤荒于嬉;行成于思,毁于随。 610

Java线程安全的计数器简单实现代码示例

主要介绍了Java线程安全的计数器简单实现代码示例,具有一定参考价值,需要的朋友可以了解下。

Android基础学习(二十)—— 线程安全

线程安全

123 1231

谷歌DreamFusion使用方法及实例详解

DreamFusion 是谷歌提出的基于文本生成3D模型的突破性技术,无需3D训练数据,通过2D扩散模型(如Imagen)与NeRF(神经辐射场)结合实现。以下为使用社区开源实现(如。)的详细步骤及实例。

主攻大数据 人工智能 物联网 安全 低空经济等方向。mtsc 、gtest特邀分享嘉宾 1042

保姆级教程:用STM32标准库搞定TIM1的PWM输出(附完整代码和避坑点)

本文提供STM32F103高级定时器TIM1的PWM输出保姆级教程,涵盖从工程搭建到完整代码实现的详细步骤。重点解析TIM1作为高级定时器的特殊配置要点,包括时钟初始化、PWM通道设置和GPIO复用功能,并附常见问题排查指南和动态调整占空比的实用技巧,帮助开发者高效实现精准PWM控制。

weixin_30673611的博客 433

高并发下的计数器实现方式:AtomicLong、LongAdder、LongAccumulator

计数器是并发编程中非常常见的一个需求,例如统计网站的访问量、计算某个操作的执行次数等等。在高并发场景下,如何实现一个线程安全的计数器是一个比较有挑战性的问题。本文将介绍几种常用的计数器实现方式,包括AtomicLong、LongAdder和LongAccumulator,并深入讲解其中的CAS操作。

weixin_40381772的博客 4283

5G物理层基础知识

1、关于RB和RE (1) RB(Resource Block,资源块)频率上连续12个子载波,时域上一个slot(时隙,14个ofdm符号) (2) RE(Resource Element,资源单元)频率上一个子载波,及时域上一个ofdm符号 注意:协议规定,5G每个时隙(非扩展CP)的符号数为14个(扩展CP情况下每个时隙有12个符号),而LTE(非扩展CP)每个时隙的符号数为7个。 简单说:一个12X14的方格,大的整个叫一个RB,每一个小块叫一个RE。另外,一个RE可存放一个调制符号(mo.

qq_39074243的博客 2万+

Java笔试面试题AI答之线程(13)

在停止线程时,推荐使用退出标志或interrupt方法,因为它们提供了更安全和可控的方式来结束线程的执行。而stop方法由于存在安全风险,应该避免使用。在实际编程中,应根据具体需求和场景选择最适合的线程停止方法。锁顺序死锁是并发编程中常见的一种死锁类型,它发生在多个线程以不同的顺序尝试获取相同的锁集合时。锁顺序死锁是指当多个线程在访问多个资源时,每个线程都按照各自的顺序获取锁,而这些顺序在某些情况下相互冲突,导致线程相互等待对方释放锁,从而形成死锁。

学无止境,止于至善 1340

避坑指南:PyCINRAD处理CINRAD雷达数据时遇到的5个典型报错及解决方案

本文针对使用PyCINRAD库处理CINRAD雷达基数据时常见的5个典型报错,提供了详细的解决方案。内容涵盖环境配置、数据读取、PPI可视化及性能优化等核心环节,重点解决了版本兼容性、数据异常处理和中文乱码等实际问题,帮助用户高效处理雷达基数据并生成准确的PPI图像。

cc789的博客 1068

09、Flutter FFI Dart Native API

本文介绍了 Dart Native API 的基本用法,解决了 Dart 与 C 异步通讯的问题

eieihihi的专栏 4397

线程安全-计数器

1、计数器实现存在线程安全问题,主要由于value++非原子性操作导致 import java.util.Random; public class Sequence { private int value; public int getNext(){ return value++; } //测试 public static void main(String[] ar...

yanghw117的博客 1143

给汽车芯片做‘体检’:手把手教你用IEC62380和SN29500估算功能安全失效率

本文详细介绍了如何使用IEC62380和SN29500标准估算汽车芯片的功能安全失效率,涵盖基础认知、方法论对比及实战计算。通过具体案例演示两种标准的应用流程,帮助工程师准确评估半导体器件的可靠性,确保符合ISO 26262标准要求。

weixin_28725553的博客 458

性能监控新范式:Folly统计指标工具包极速上手

你是否还在为应用性能监控发愁?服务器响应延迟波动大却找不到瓶颈?用户投诉卡顿但日志里只有枯燥的数字?本文将带你掌握Facebook开源C++库Folly中最实用的性能统计工具,无需复杂配置即可实现专业级监控,让你5分钟内搭建起精准的性能观测体系。 读完本文你将获得: - 3个核心统计组件的零代码集成方案 - 99%分位延迟计算的最优实践 - 线程安全的计数器实现模板 - 生产环境验证的性能监控架...

gitblog_00358的博客 364

【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码

从PointNet到PointNet++理论及代码详解1. 点云是什么1.1 三维数据的表现形式1.2 为什么使用点云1.3 点云上以往的相关工作2. PointNet2.1 基于点云的置换不变性2.1.1 由对称函数到PointNet(vanilla)2.1.2 理论证明2.2 基于点云的旋转不变性2.3 网络总体结构2.4 实验结果和网络的鲁棒性2.5 代码解析3. PointNet++3.1...

小执着的博客 8万+

基于LSTM算法实现交通流量预测(Pytorch版)

本研究采用PyTorch框架,设计并实现了一种基于LSTM(Long Short-Term Memory)网络的交通流量预测模型。针对时序性显著的交通流量数据,模型首先将多节点、多通道的时空信息整合为一维特征输入至多层LSTM单元,利用其捕捉长期依赖及短期波动的能力进行深度学习。全连接层随后调整时间步长以适应预测周期需求。模型结构灵活,能适应不同节点数、输入输出长度及通道配置,实现在给定历史流量数据基础上对未来交通流量的精准预测,为交通管理与规划提供数据驱动支持。

打酱油的葫芦娃 4637

八大排序算法比较与交换次数统计工具

排序算法的性能本质不在于运行时间,而在于其核心原子操作——比较与交换。理解冒泡、快排、归并等算法在不同数据分布下的实际行为,需剥离CPU负载、缓存、语言开销等干扰,直击算法逻辑内核。比较次数反映决策频次,交换次数体现数据搬移成本,二者共同构成算法的‘行为指纹’。该统计方法广泛应用于算法教学验证、教材案例复现、性能瓶颈定位及增量策略评估(如希尔排序序列选型)。通过细粒度捕获每一次比较和交换,可真实揭示插入排序的自适应性、选择排序的固定比较特性,以及计数排序零比较的本质差异。

weixin_32430941的博客 261

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Spark-累加器Accumulator图文详解

Spark累加器

喻师傅的学习笔记 848

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

3000+ 张成品设计随用随取:戴森球计划工厂蓝图库 FactoryBluePrints

FactoryBluePrints 是面向《戴森球计划》的社区工厂蓝图仓库,汇集数千张经过社区实测的戴森球计划蓝图,覆盖开荒、产线、能源、物流到戴森球建造的完整流程。无论你是刚起步、还在手动画传送带的新手,还是想继续做工厂布局优化的老玩家,都可以直接导入现成的工厂设计模板,把时间花在产能规划上而不是重复摆建筑。 ## 适合哪些玩家使用 - **开荒期新手**:不想自己研究产线比例,可以直接取用

gitblog_00119的博客 206

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

4 多线程统计次数问题:即count++

多线程统计次数问题:即count++ 场景:日志需要统计每天数据上传的次数和上传的数据量。      如果是单线程可以使用简单的int count = 0;count++,但很多情况都是多线程环境所以就不能单纯的使用count++了!!!      多线程环境采用 java.util.concurrent.atomic 下的AtomicLong类,该类的介绍可看API文档。可以用原子方式更新...

xiaoxiaoniaoQ的博客 3476

设计线程安全的高性能计数器

方案适用场景优点缺点AtomicLong低并发,简单计数无锁,CAS 轻量级高并发时 CAS 自旋LongAdder高并发写,读少(推荐)分段累加,减少竞争sum()稍慢复杂逻辑,低性能要求简单易用锁竞争高时性能差极高吞吐,允许短暂不一致无竞争,性能极高读取可能不精确分片计数(如按 key 统计)扩展性强,支持多 key内存占用较高。

2203_75376529的博客 1613

最全面的jemalloc计数器实现:从源码到内存统计实战

你是否曾为内存泄漏问题困扰数周?是否想知道生产环境中内存碎片如何悄然侵蚀系统性能?jemalloc的counter计数器组件正是解决这些问题的关键。本文将带你深入jemalloc源码,剖析counter模块的实现原理,掌握内存使用统计的核心方法,让你轻松应对复杂的内存管理挑战。读完本文,你将能够:理解计数器的线程安全设计、掌握内存使用统计的实现方式、学会利用jemalloc的统计功能优化应用性能。...

gitblog_00404的博客 501

什么是线程安全?

在编程里,特别是当程序能同时做很多事情(多线程)时,线程安全就显得尤为重要了。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 5400

基于CAS线程安全实现计数器

 在多线程环境下,实现一个CAS原理的线程安全的技术器,并与不使用CAS算法的计数器进行比较。 package com.feiyu.text; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * @Created by 猎风工作...

青衣煮茶 1万+

java 线程安全 计数_Java线程安全的计数器简单实现代码示例

前几天工作中一段业务代码需要一个变量每天从1开始递增。为此自己简单的封装了一个线程安全的计数器,可以让一个变量每天从1开始递增。当然了,如果项目在运行中发生重启,即便日期还是当天,还是会从1开始重新计数。所以把计数器的值存储在数据库中会更靠谱,不过这不影响这段代码的价值,现在贴出来,供有需要的人参考。package com.hikvision.cms.rvs.common.util;import ...

weixin_39708854的博客 335

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

我对Scala和函数式编程比较陌生,我喜欢使用不可变对象的想法,我可以避免许多线程安全陷阱.有一件事仍然困扰着我,这是用于教授线程安全的经典示例 – 共享计数器.我想知道是否可以实现线程安全计数器(在此示例中为请求计数器),使用不可变对象和功能概念,并完全避免同步.所以在这里参考首先是计数器的经典可变版本(请原谅我的公共成员变量,仅为了简洁示例)可变,非线程安全版本:public class Se...

weixin_31232695的博客 372
上一篇: build qt webkit with vs2008 in windows
下一篇: ubuntu下mysql workbench 没响应的解决办法
fancyerII
博客等级 码龄23年 48粉丝 164原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值