JAVA编程思想笔记 : 并发 [ 三 ]
性能调优
lock 和 synchronized
//: concurrency/SynchronizationComparisons.java
package concurrency; /* Added by Eclipse.py */
// Comparing the performance of explicit Locks
// and Atomics versus the synchronized keyword.
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.*;
import static net.mindview.util.Print.*;
abstract class Accumulator {
public static long cycles = 50000L;
// Number of Modifiers and Readers during each test:
private static final int N = 4;
public static ExecutorService exec =
Executors.newFixedThreadPool(N*2);
private static CyclicBarrier barrier =
new CyclicBarrier(N*2 + 1);
protected volatile int index = 0;
protected volatile long value = 0;
protected long duration = 0;
protected String id = "error";
protected final static int SIZE = 100000;
protected static int[] preLoaded = new int[SIZE];
static {
// Load the array of random numbers:
Random rand = new Random(47);
for(int i = 0; i < SIZE; i++)
preLoaded[i] = rand.nextInt();
}
public abstract void accumulate();
public abstract long read();
private class Modifier implements Runnable {
public void run() {
for(long i = 0; i < cycles; i++)
accumulate();
try {
barrier.await();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
private class Reader implements Runnable {
private volatile long value;
public void run() {
for(long i = 0; i < cycles; i++)
value = read();
try {
barrier.await();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
public void timedTest() {
long start = System.nanoTime();
for(int i = 0; i < N; i++) {
exec.execute(new Modifier());
exec.execute(new Reader());
}
try {
barrier.await();
} catch(Exception e) {
throw new RuntimeException(e);
}
duration = System.nanoTime() - start;
printf("%-13s: %13d\n", id, duration);
}
public static void
report(Accumulator acc1, Accumulator acc2) {
printf("%-22s: %.2f\n", acc1.id + "/" + acc2.id,
(double)acc1.duration/(double)acc2.duration);
}
}
class BaseLine extends Accumulator {
{ id = "BaseLine"; }
public void accumulate() {
if( index < SIZE){
value += preLoaded[index++];
if(index >= SIZE) index = 0;
}
}
public long read() { return value; }
}
class SynchronizedTest extends Accumulator {
{ id = "synchronized"; }
public synchronized void accumulate() {
value += preLoaded[index++];
if(index >= SIZE) index = 0;
}
public synchronized long read() {
return value;
}
}
class LockTest extends Accumulator {
{ id = "Lock"; }
private Lock lock = new ReentrantLock();
public void accumulate() {
lock.lock();
try {
value += preLoaded[index++];
if(index >= SIZE) index = 0;
} finally {
lock.unlock();
}
}
public long read() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}
}
class AtomicTest extends Accumulator {
{ id = "Atomic"; }
private AtomicInteger index = new AtomicInteger(0);
private AtomicLong value = new AtomicLong(0);
public void accumulate() {
// Oops! Relying on more than one Atomic at
// a time doesn't work. But it still gives us
// a performance indicator:
int i = index.getAndIncrement();
if( index.get() < SIZE){
value.getAndAdd(preLoaded[i]);
if(++i >= SIZE)
index.set(0);
}
}
public long read() { return value.get(); }
}
public class SynchronizationComparisons {
static BaseLine baseLine = new BaseLine();
static SynchronizedTest synch = new SynchronizedTest();
static LockTest lock = new LockTest();
static AtomicTest atomic = new AtomicTest();
static void test() {
print("============================");
printf("%-12s : %13d\n", "Cycles", Accumulator.cycles);
baseLine.timedTest();
synch.timedTest();
lock.timedTest();
atomic.timedTest();
Accumulator.report(synch, baseLine);
Accumulator.report(lock, baseLine);
Accumulator.report(atomic, baseLine);
Accumulator.report(synch, lock);
Accumulator.report(synch, atomic);
Accumulator.report(lock, atomic);
}
public static void main(String[] args) {
int iterations = 5; // Default
if(args.length > 0) // Optionally change iterations
iterations = new Integer(args[0]);
// The first time fills the thread pool:
print("Warmup");
baseLine.timedTest();
// Now the initial test doesn't include the cost
// of starting the threads for the first time.
// Produce multiple data points:
for(int i = 0; i < iterations; i++) {
test();
Accumulator.cycles *= 2;
}
Accumulator.exec.shutdown();
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:62371', transport: 'socket'
Warmup
BaseLine : 21694209
============================
Cycles : 50000
BaseLine : 2180204
synchronized : 42437398
Lock : 30372376
Atomic : 26275467
synchronized/BaseLine : 19.46
Lock/BaseLine : 13.93
Atomic/BaseLine : 12.05
synchronized/Lock : 1.40
synchronized/Atomic : 1.62
Lock/Atomic : 1.16
============================
Cycles : 100000
BaseLine : 5193179
synchronized : 82977464
Lock : 31370928
Atomic : 11210371
synchronized/BaseLine : 15.98
Lock/BaseLine : 6.04
Atomic/BaseLine : 2.16
synchronized/Lock : 2.65
synchronized/Atomic : 7.40
Lock/Atomic : 2.80
============================
Cycles : 200000
BaseLine : 8938838
synchronized : 165124963
Lock : 78268801
Atomic : 13180858
synchronized/BaseLine : 18.47
Lock/BaseLine : 8.76
Atomic/BaseLine : 1.47
synchronized/Lock : 2.11
synchronized/Atomic : 12.53
Lock/Atomic : 5.94
============================
Cycles : 400000
BaseLine : 24426392
synchronized : 331777960
Lock : 115546684
Atomic : 29905100
synchronized/BaseLine : 13.58
Lock/BaseLine : 4.73
Atomic/BaseLine : 1.22
synchronized/Lock : 2.87
synchronized/Atomic : 11.09
Lock/Atomic : 3.86
============================
Cycles : 800000
BaseLine : 34345855
synchronized : 633854425
Lock : 245733266
Atomic : 87583065
synchronized/BaseLine : 18.46
Lock/BaseLine : 7.15
Atomic/BaseLine : 2.55
synchronized/Lock : 2.58
synchronized/Atomic : 7.24
Lock/Atomic : 2.81
============================
Cycles : 1600000
BaseLine : 62631708
synchronized : 1594457825
Lock : 654792500
Atomic : 138332107
synchronized/BaseLine : 25.46
Lock/BaseLine : 10.45
Atomic/BaseLine : 2.21
synchronized/Lock : 2.44
synchronized/Atomic : 11.53
Lock/Atomic : 4.73
============================
Cycles : 3200000
BaseLine : 128165186
synchronized : 3528972948
Lock : 1278760479
Atomic : 285986269
synchronized/BaseLine : 27.53
Lock/BaseLine : 9.98
Atomic/BaseLine : 2.23
synchronized/Lock : 2.76
synchronized/Atomic : 12.34
Lock/Atomic : 4.47
============================
Cycles : 6400000
BaseLine : 220485251
synchronized : 6981991134
Lock : 2650398226
Atomic : 500422566
synchronized/BaseLine : 31.67
Lock/BaseLine : 12.02
Atomic/BaseLine : 2.27
synchronized/Lock : 2.63
synchronized/Atomic : 13.95
Lock/Atomic : 5.30
整理成表格:
no | Cycles | BaseLine | synchronized | Lock | Atomic |
1 | 50000 | 2180204 | 42437398 | 30372376 | 26275467 |
2 | 100000 | 5193179 | 82977464 | 31370928 | 11210371 |
3 | 200000 | 8938838 | 165124963 | 78268801 | 13180858 |
4 | 400000 | 24426392 | 331777960 | 115546684 | 29905100 |
5 | 800000 | 34345855 | 633854425 | 245733266 | 87583065 |
6 | 1600000 | 62631708 | 1594457825 | 654792500 | 138332107 |
7 | 3200000 | 128165186 | 3528972948 | 1278760479 | 285986269 |
8 | 6400000 | 220485251 | 6981991134 | 2650398226 | 500422566 |
使用 Lock 通常会比使用 synchronized 要高效
免锁容器
CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器",Java并发包中类似的容器还有CopyOnWriteSet。
优缺点分析
了解了CopyOnWriteArrayList的实现原理,分析它的优缺点及使用场景就很容易了。
优点:
读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。Java的list在遍历时,若中途有别的线程对list容器进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其"读写分离"的思想,遍历和修改操作分别作用在不同的list容器,所以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了
缺点:
缺点也很明显,一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。
CopyOnWriteArraySet 将使用CopyOnWriteArrayList来实现其免锁行为
ConcurrentHashMap和 ConcurrentLinkedQueue 使用了类似的技术,允许并发的读取和写入.但是容器中只有部分内容而不是整个容器可以被复制和修改.
ConcurrentHashMap不会抛出 ConcurrentModificationException.
乐观锁
Type Read time Write time
Synched ArrayList 10r 0w 3975043910 0
Synched ArrayList 10r 0w 2766145687 0
Synched ArrayList 10r 0w 2324410921 0
Synched ArrayList 10r 0w 2352972749 0
Synched ArrayList 10r 0w 2511789031 0
Synched ArrayList 10r 0w 2987712606 0
Synched ArrayList 10r 0w 2602829236 0
Synched ArrayList 10r 0w 3502788085 0
Synched ArrayList 10r 0w 4335015877 0
Synched ArrayList 10r 0w 4047738828 0
CopyOnWriteArrayList 10r 0w 127857882 0
CopyOnWriteArrayList 10r 0w 62679837 0
CopyOnWriteArrayList 10r 0w 54443863 0
CopyOnWriteArrayList 10r 0w 56359211 0
CopyOnWriteArrayList 10r 0w 74350707 0
CopyOnWriteArrayList 10r 0w 62574412 0
CopyOnWriteArrayList 10r 0w 60151492 0
CopyOnWriteArrayList 10r 0w 68195080 0
CopyOnWriteArrayList 10r 0w 74290655 0
CopyOnWriteArrayList 10r 0w 62879388 0
预计相差 40 倍
Synched ArrayList 9r 1w 4351248439 519078520
readTime + writeTime = 4870326959
Synched ArrayList 9r 1w 4580132832 528211025
readTime + writeTime = 5108343857
Synched ArrayList 9r 1w 4535477318 530243150
readTime + writeTime = 5065720468
Synched ArrayList 9r 1w 3729192259 449021236
readTime + writeTime = 4178213495
Synched ArrayList 9r 1w 4310570520 516373800
readTime + writeTime = 4826944320
Synched ArrayList 9r 1w 3727406116 444126621
readTime + writeTime = 4171532737
Synched ArrayList 9r 1w 5088467838 581730237
readTime + writeTime = 5670198075
Synched ArrayList 9r 1w 3871264858 467694613
readTime + writeTime = 4338959471
Synched ArrayList 9r 1w 3907490866 475651205
readTime + writeTime = 4383142071
Synched ArrayList 9r 1w 4857326451 572377421
readTime + writeTime = 5429703872
CopyOnWriteArrayList 9r 1w 64259585 58038121
readTime + writeTime = 122297706
CopyOnWriteArrayList 9r 1w 103041865 55306617
readTime + writeTime = 158348482
CopyOnWriteArrayList 9r 1w 76859340 45666997
readTime + writeTime = 122526337
CopyOnWriteArrayList 9r 1w 82963384 49150571
readTime + writeTime = 132113955
CopyOnWriteArrayList 9r 1w 85530058 47494007
readTime + writeTime = 133024065
CopyOnWriteArrayList 9r 1w 156166751 61169655
readTime + writeTime = 217336406
CopyOnWriteArrayList 9r 1w 102234854 50495800
readTime + writeTime = 152730654
CopyOnWriteArrayList 9r 1w 118083485 59992123
readTime + writeTime = 178075608
CopyOnWriteArrayList 9r 1w 168668483 60294659
readTime + writeTime = 228963142
CopyOnWriteArrayList 9r 1w 83152493 52633779
readTime + writeTime = 135786272
预计相差 30 倍
Synched ArrayList 5r 5w 1859681520 3059611972
readTime + writeTime = 4919293492
Synched ArrayList 5r 5w 2339497789 3231858118
readTime + writeTime = 5571355907
Synched ArrayList 5r 5w 1759631869 2999467850
readTime + writeTime = 4759099719
Synched ArrayList 5r 5w 1872095383 3013864853
readTime + writeTime = 4885960236
Synched ArrayList 5r 5w 2991087849 3226872592
readTime + writeTime = 6217960441
Synched ArrayList 5r 5w 2434089947 3523933235
readTime + writeTime = 5958023182
Synched ArrayList 5r 5w 2536545986 3119941132
readTime + writeTime = 5656487118
Synched ArrayList 5r 5w 2571197431 3003374484
readTime + writeTime = 5574571915
Synched ArrayList 5r 5w 2222675410 2791449002
readTime + writeTime = 5014124412
Synched ArrayList 5r 5w 1583914850 2689629756
readTime + writeTime = 4273544606
CopyOnWriteArrayList 5r 5w 142259670 1206935112
readTime + writeTime = 1349194782
CopyOnWriteArrayList 5r 5w 49615047 995217184
readTime + writeTime = 1044832231
CopyOnWriteArrayList 5r 5w 31987043 977226939
readTime + writeTime = 1009213982
CopyOnWriteArrayList 5r 5w 66506805 1040415224
readTime + writeTime = 1106922029
CopyOnWriteArrayList 5r 5w 35032835 994549959
readTime + writeTime = 1029582794
CopyOnWriteArrayList 5r 5w 38461110 1002445848
readTime + writeTime = 1040906958
CopyOnWriteArrayList 5r 5w 50651685 1071667187
readTime + writeTime = 1122318872
CopyOnWriteArrayList 5r 5w 32006848 1001262532
readTime + writeTime = 1033269380
CopyOnWriteArrayList 5r 5w 36295220 1011740649
readTime + writeTime = 1048035869
CopyOnWriteArrayList 5r 5w 34283434 1050960270
readTime + writeTime = 1085243704
预计相差 4 倍
CopyOnWriteArrayList性能 要比 SynchronizedArrayList 性能好一些. 当读的情况多的时候,会有几十倍的差距.
当读写数据量大小趋向于平均时, 性能还有将近四倍的差距.
比较各种 Map 实现
Type Read time Write time
Synched HashMap 10r 0w 6242418056 0
Synched HashMap 10r 0w 4146402296 0
Synched HashMap 10r 0w 5575418578 0
Synched HashMap 10r 0w 3834073584 0
Synched HashMap 10r 0w 5194782005 0
Synched HashMap 10r 0w 5161536963 0
Synched HashMap 10r 0w 4444520893 0
Synched HashMap 10r 0w 3871868695 0
Synched HashMap 10r 0w 4408989207 0
Synched HashMap 10r 0w 8023118598 0
ConcurrentHashMap 10r 0w 344685546 0
ConcurrentHashMap 10r 0w 346848415 0
ConcurrentHashMap 10r 0w 318704071 0
ConcurrentHashMap 10r 0w 405478178 0
ConcurrentHashMap 10r 0w 207930162 0
ConcurrentHashMap 10r 0w 366067455 0
ConcurrentHashMap 10r 0w 226500276 0
ConcurrentHashMap 10r 0w 296423990 0
ConcurrentHashMap 10r 0w 320249183 0
ConcurrentHashMap 10r 0w 508154405 0
读取性能差 10 倍以上
Synched HashMap 9r 1w 6513091741 753915689
readTime + writeTime = 7267007430
Synched HashMap 9r 1w 6028976406 641421250
readTime + writeTime = 6670397656
Synched HashMap 9r 1w 5676651670 653679779
readTime + writeTime = 6330331449
Synched HashMap 9r 1w 5908498114 494457577
readTime + writeTime = 6402955691
Synched HashMap 9r 1w 7834818531 844974551
readTime + writeTime = 8679793082
Synched HashMap 9r 1w 5914246757 645557937
readTime + writeTime = 6559804694
Synched HashMap 9r 1w 7138638960 744661626
readTime + writeTime = 7883300586
Synched HashMap 9r 1w 6789718783 710857815
readTime + writeTime = 7500576598
Synched HashMap 9r 1w 5310600463 599121405
readTime + writeTime = 5909721868
Synched HashMap 9r 1w 5655007305 586903118
readTime + writeTime = 6241910423
ConcurrentHashMap 9r 1w 216104674 54419560
readTime + writeTime = 270524234
ConcurrentHashMap 9r 1w 294262252 40927173
readTime + writeTime = 335189425
ConcurrentHashMap 9r 1w 264142918 43273241
readTime + writeTime = 307416159
ConcurrentHashMap 9r 1w 273924527 48728635
readTime + writeTime = 322653162
ConcurrentHashMap 9r 1w 369514606 50730634
readTime + writeTime = 420245240
ConcurrentHashMap 9r 1w 219419103 38947284
readTime + writeTime = 258366387
ConcurrentHashMap 9r 1w 252190432 30225329
readTime + writeTime = 282415761
ConcurrentHashMap 9r 1w 228296180 25051090
readTime + writeTime = 253347270
ConcurrentHashMap 9r 1w 303395962 49612912
readTime + writeTime = 353008874
ConcurrentHashMap 9r 1w 171637818 35856054
readTime + writeTime = 207493872
预计相差 25 倍以上.
Synched HashMap 5r 5w 3787200263 3601518353
readTime + writeTime = 7388718616
Synched HashMap 5r 5w 3089274985 2733346333
readTime + writeTime = 5822621318
Synched HashMap 5r 5w 3408395059 3113962082
readTime + writeTime = 6522357141
Synched HashMap 5r 5w 3981206639 3679965007
readTime + writeTime = 7661171646
Synched HashMap 5r 5w 3265915194 3142623898
readTime + writeTime = 6408539092
Synched HashMap 5r 5w 3164752807 3000101498
readTime + writeTime = 6164854305
Synched HashMap 5r 5w 3336219924 3014104874
readTime + writeTime = 6350324798
Synched HashMap 5r 5w 3124944592 2991122381
readTime + writeTime = 6116066973
Synched HashMap 5r 5w 3977208930 3839928054
readTime + writeTime = 7817136984
Synched HashMap 5r 5w 3074772608 2874037633
readTime + writeTime = 5948810241
ConcurrentHashMap 5r 5w 99540221 462089771
readTime + writeTime = 561629992
ConcurrentHashMap 5r 5w 240567089 518136870
readTime + writeTime = 758703959
ConcurrentHashMap 5r 5w 155490877 432835809
readTime + writeTime = 588326686
ConcurrentHashMap 5r 5w 220516994 483831256
readTime + writeTime = 704348250
ConcurrentHashMap 5r 5w 216032229 572084619
readTime + writeTime = 788116848
ConcurrentHashMap 5r 5w 197179986 620970499
readTime + writeTime = 818150485
ConcurrentHashMap 5r 5w 254407618 544484450
readTime + writeTime = 798892068
ConcurrentHashMap 5r 5w 208138769 501331795
readTime + writeTime = 709470564
ConcurrentHashMap 5r 5w 180873142 492012085
readTime + writeTime = 672885227
ConcurrentHashMap 5r 5w 164806795 559711679
readTime + writeTime = 724518474
预计相差 10 倍以上
ConcurrentHashMap 完虐 synchronizedMap
乐观加锁
//: concurrency/FastSimulation.java
package concurrency; /* Added by Eclipse.py */
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class FastSimulation {
static final int N_ELEMENTS = 100000;
static final int N_GENES = 30;
static final int N_EVOLVERS = 50;
static final AtomicInteger[][] GRID =
new AtomicInteger[N_ELEMENTS][N_GENES];
static Random rand = new Random(47);
static class Evolver implements Runnable {
public void run() {
while(!Thread.interrupted()) {
// Randomly select an element to work on:
int element = rand.nextInt(N_ELEMENTS);
for(int i = 0; i < N_GENES; i++) {
int previous = element - 1;
if(previous < 0) previous = N_ELEMENTS - 1;
int next = element + 1;
if(next >= N_ELEMENTS) next = 0;
int oldvalue = GRID[element][i].get();
// Perform some kind of modeling calculation:
int newvalue = oldvalue +
GRID[previous][i].get() + GRID[next][i].get();
newvalue /= 3; // Average the three values
if(!GRID[element][i]
.compareAndSet(oldvalue, newvalue)) {
// Policy here to deal with failure. Here, we
// just report it and ignore it; our model
// will eventually deal with it.
print("Old value changed from " + oldvalue);
}
}
}
}
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i < N_ELEMENTS; i++)
for(int j = 0; j < N_GENES; j++)
GRID[i][j] = new AtomicInteger(rand.nextInt(1000));
for(int i = 0; i < N_EVOLVERS; i++)
exec.execute(new Evolver());
TimeUnit.SECONDS.sleep(5);
exec.shutdownNow();
}
} /* (Execute to see output) *///:~
ReadWriteLock
//: concurrency/ReaderWriterList.java
package concurrency; /* Added by Eclipse.py */
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class ReaderWriterList<T> {
private ArrayList<T> lockedList;
// Make the ordering fair:
private ReentrantReadWriteLock lock =
new ReentrantReadWriteLock(true);
public ReaderWriterList(int size, T initialValue) {
lockedList = new ArrayList<T>(
Collections.nCopies(size, initialValue));
}
public T set(int index, T element) {
Lock wlock = lock.writeLock();
wlock.lock();
try {
return lockedList.set(index, element);
} finally {
wlock.unlock();
}
}
public T get(int index) {
Lock rlock = lock.readLock();
rlock.lock();
try {
// Show that multiple readers
// may acquire the read lock:
if(lock.getReadLockCount() > 1)
print(lock.getReadLockCount());
return lockedList.get(index);
} finally {
rlock.unlock();
}
}
public static void main(String[] args) throws Exception {
new ReaderWriterListTest(30, 1);
}
}
class ReaderWriterListTest {
ExecutorService exec = Executors.newCachedThreadPool();
private final static int SIZE = 100;
private static Random rand = new Random(47);
private ReaderWriterList<Integer> list =
new ReaderWriterList<Integer>(SIZE, 0);
private class Writer implements Runnable {
public void run() {
try {
for(int i = 0; i < 20; i++) { // 2 second test
list.set(i, rand.nextInt());
TimeUnit.MILLISECONDS.sleep(100);
}
} catch(InterruptedException e) {
// Acceptable way to exit
}
print("Writer finished, shutting down");
exec.shutdownNow();
}
}
private class Reader implements Runnable {
public void run() {
try {
while(!Thread.interrupted()) {
for(int i = 0; i < SIZE; i++) {
list.get(i);
TimeUnit.MILLISECONDS.sleep(1);
}
}
} catch(InterruptedException e) {
// Acceptable way to exit
}
}
}
public ReaderWriterListTest(int readers, int writers) {
for(int i = 0; i < readers; i++)
exec.execute(new Reader());
for(int i = 0; i < writers; i++)
exec.execute(new Writer());
}
} /* (Execute to see output) *///:~