java的BitSet不是线程安全的,所以多线程的时候h要加锁。
1 直接加锁整个BitSet 用时:3.4秒
2 BitSet拆成更小的粒度 用时:3.6秒
3 使用并发的BitSet,自己写了个AtomicBitSet 用时:3.3秒
从测试结果来看 性能都差不多
感觉有点疑惑,在我的想象中2还和3应该会比1好不少的啊
下面3个测试分别对应3种方式
附件是完整代码
测试1
package com.eyu.gift.service;
import java.util.BitSet;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import org.junit.Test;
/**
* 用时3.4秒
* @author bean
*/
public class BitsetTest1 {
public static final int NUM = 50000000;
@Test
public void mutiThreadTest() {
BitSet bitset = new BitSet();
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(20);
int total = NUM / 10;
Random random = new Random(1234);
for (int i = 1; i < total; i++) {
int targrt = random.nextInt(NUM);
if (targrt % 5 == 0) {
executorService.execute(new Task1(bitset, i));
} else {
executorService.execute(new ReadBitTask1(bitset, i));
}
}
executorService.shutdown();
while (true) {
if (executorService.isTerminated()) {
break;
}
}
}
}
class Task1 implements Runnable {
private int id;
private BitSet bitset;
public Task1(BitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
synchronized (bitset) {
bitset.set(id);
}
}
}
class ReadBitTask1 implements Runnable {
private int id;
private BitSet bitset;
public ReadBitTask1(BitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
synchronized (bitset) {
bitset.get(id);
}
}
}
测试2
package com.eyu.gift.service;
import java.util.BitSet;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import org.junit.Test;
/**
* 用时3.6秒
* @author bean
*/
public class BitsetTest2 {
public static final int NUM = 50000000;
static Object[] locks;
static {
locks = new Object[10000];
for (int i = 0; i < 10000; i++) {
locks[i] = new Object();
}
}
@Test
public void mutiThreadTest() {
BitSet bitset = new BitSet();
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(20);
int total = NUM / 10;
Random random = new Random(1234);
for (int i = 1; i < total; i++) {
int targrt = random.nextInt(NUM);
if (targrt % 5 == 0) {
executorService.execute(new Task2(bitset, i));
} else {
executorService.execute(new ReadTask2(bitset, i));
}
}
executorService.shutdown();
while (true) {
if (executorService.isTerminated()) {
break;
}
}
}
public static Object getLock(int i) {
return locks[i % 10000];
}
}
class Task2 implements Runnable {
private int id;
private BitSet bitset;
public Task2(BitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
Object lockObject = BitsetTest2.getLock(id);
synchronized (lockObject) {
bitset.set(id);
}
}
}
class ReadTask2 implements Runnable {
private int id;
private BitSet bitset;
public ReadTask2(BitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
Object lockObject = BitsetTest2.getLock(id);
synchronized (lockObject) {
bitset.get(id);
}
}
}
测试3
package com.eyu.gift.service;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import org.junit.Test;
/**
* 用时3.3秒
* @author bean
*/
public class BitSetTest3 {
public static final int NUM = 50000000;
@Test
public void mutiAtomThreadTest() {
AtomicBitSet bitset = new AtomicBitSet(NUM);
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(20);
int total = NUM / 10;
Random random = new Random(1234);
for (int i = 1; i < total; i++) {
int targrt = random.nextInt(NUM);
if (targrt % 5 == 0) {
executorService.execute(new Task3(bitset, i));
} else {
executorService.execute(new ReadTask3(bitset, i));
}
}
executorService.shutdown();
while (true) {
if (executorService.isTerminated()) {
break;
}
}
}
}
class Task3 implements Runnable {
private int id;
private AtomicBitSet bitset;
public Task3(AtomicBitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
bitset.set(id);
}
}
class ReadTask3 implements Runnable {
private int id;
private AtomicBitSet bitset;
public ReadTask3(AtomicBitSet bitset, int id) {
this.bitset = bitset;
this.id = id;
}
@Override
public void run() {
bitset.get(id);
}
}
并发安全BitSet:
package com.eyu.gift.service;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicBitSet {
private final AtomicIntegerArray array;
public AtomicBitSet(int length) {
int intLength = (length + 31) / 32;
array = new AtomicIntegerArray(intLength);
}
public void set(long n) {
int bit = 1 << n;
int idx = (int) (n >>> 5);
while (true) {
int num = array.get(idx);
int num2 = num | bit;
if (num == num2 || pareAndSet(idx, num, num2))
return;
}
}
public boolean get(long n) {
int bit = 1 << n;
int idx = (int) (n >>> 5);
int num = array.get(idx);
return (num & bit) != 0;
}
}