シングルスレッドを使用する
カウンタの値はシングルスレッドで変更されるので問題ないが、各演算の結果は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
参考