Java: シングルスレッドのカウンタからマルチスレッドのデータ同期同期およびアトミッククラス Atomic へ

シングルスレッドを使用する

カウンタの値はシングルスレッドで変更されるので問題ないが、各演算の結果は10000だがプログラムに時間がかかる

package com.example;

/**
 * 计数器
 */
class Counter {
    
    
    private static long count;

    public static long getCount() {
    
    
        return count;
    }

    public static void incrementCount() {
    
    
        count++;
    }
}


public class Demo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        long count = Counter.getCount();
        System.out.println(count);
        // 0

        for (int i = 0; i < 10000; i++) {
    
    
            try {
    
    
                Thread.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            Counter.incrementCount();
        }
        
        count = Counter.getCount();
        System.out.println(count);
        // 10000
    }
}

マルチスレッドを使用する

シングルスレッドでカウンタの値を変更し、実行速度は向上しますが、実行結果が毎回ばらつき、結果が10000にならない

package com.example;

import java.util.ArrayList;
import java.util.List;

/**
 * 计数器
 */
class Counter {
    
    
    private static long count;

    public static long getCount() {
    
    
        return count;
    }

    public static void incrementCount() {
    
    
        count++;
    }
}


public class Demo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        long count = Counter.getCount();
        System.out.println(count);
        // 0

        List<Thread> list = new ArrayList<>();

        // 启动10000个线程同时访问计数器
        for (int i = 0; i < 10000; i++) {
    
    
            Thread thread = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    try {
    
    
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                    Counter.incrementCount();
                }
            });
            list.add(thread);
        }

        for (Thread thread : list) {
    
    
            thread.start();
        }

        for (Thread thread : list) {
    
    
            thread.join();
        }

        count = Counter.getCount();
        System.out.println(count);
    }
}

の結果

第一次:9910
第二次:9912
第三次:9910

マルチスレッド + 同期を使用する

マルチスレッド ロック後の最終結果は 10000 です

package com.example;

import java.util.ArrayList;
import java.util.List;

/**
 * 计数器
 */
class Counter {
    
    
    private static long count;

    public static long getCount() {
    
    
        return count;
    }

    public static synchronized void incrementCount() {
    
    
        count++;
    }
}


public class Demo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        long count = Counter.getCount();
        System.out.println(count);
        // 0

        List<Thread> list = new ArrayList<>();

        // 启动10000个线程同时访问计数器
        for (int i = 0; i < 10000; i++) {
    
    
            Thread thread = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    try {
    
    
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                    Counter.incrementCount();
                }
            });
            list.add(thread);
        }

        for (Thread thread : list) {
    
    
            thread.start();
        }

        for (Thread thread : list) {
    
    
            thread.join();
        }

        count = Counter.getCount();
        System.out.println(count);
    }
}

の結果

第一次:10000
第二次:10000
第三次:10000

マルチスレッド + アトミック クラス AtomicLong を使用する

アトミック クラス AtomicLong は、マルチスレッドでカウンターを実装するために使用され、最終結果は 10000 です。

原則はCAS(比較して設定) です。

  • まず元の値と期待値を比較し、等しい場合は新しい値に変更します。
  • 等しくない場合、変更は失敗します

疑似コードは次のとおりです

bool compareAndSet(oldValue, expectValue, updateValue){
    
    
    if(oldValue == expectValue){
    
    
        oldValue = updateValue
        // update success
    } else{
    
    
        // update fail
    }
}
package com.example;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 计数器
 */
class Counter {
    
    
    private static AtomicLong count = new AtomicLong(0);

    public static long getCount() {
    
    
        return count.get();
    }

    public static void incrementCount() {
    
    
        count.incrementAndGet();
    }
}


public class Demo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        long count = Counter.getCount();
        System.out.println(count);
        // 0

        List<Thread> list = new ArrayList<>();

        // 启动10000个线程同时访问计数器
        for (int i = 0; i < 10000; i++) {
    
    
            Thread thread = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    try {
    
    
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                    Counter.incrementCount();
                }
            });
            list.add(thread);
        }

        for (Thread thread : list) {
    
    
            thread.start();
        }

        for (Thread thread : list) {
    
    
            thread.join();
        }

        count = Counter.getCount();
        System.out.println(count);
    }
}

の結果

第一次:10000
第二次:10000
第三次:10000

参考

  1. Atomic-Liao Xuefeng の公式 Web サイトの使用方法
  2. CASロック機構(ロック無し、スピンロック、楽観ロック、軽量ロック)
  3. Javaのアトミッククラス

おすすめ

転載: blog.csdn.net/mouday/article/details/130923836