(目录)

使用单线程

单线程修改计数器的值,没有发生问题,每次运行结果都是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

使用多线程 + synchronized

多线程加锁后,最后结果都是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(Compare and Set):

  • 先比较原始值和预期值,如果相等,则修改为新值;
  • 不相等则修改失败

伪代码如下

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-廖雪峰的官方网站]
  2. CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)
  3. java中的Atomic类