Atomic:使用自旋锁,如果线程多,执行时间长会消耗CPU资源,性能消耗在切换线程上,所以如果线程少,执行时间不长,推荐使用自旋锁来保证线程安全。使用场景:线程少,加锁时间短。
Synchronized:系统锁,在没有锁升的情况下属于总量级锁,每次加锁都要向操作系统申请加锁,加锁时间慢,使用该锁存在同步队列,即如果没有抢到锁的线程会加入到队列中,等到锁得到释放才会通知去获取锁,不会导致大量CPU来回切换线程。适用场景:线程数量多,加锁时间长。
LongAdder:分段锁,在多个线程执行时存在多个锁,分别管理多个共享资源,当所有线程都结束后再将这些锁管控的共享资源结果结合起来得到最后结果。使用场景:线程数量多。
注意:实际情况中,使用那种锁机制,还是得提前判定锁的数量和加锁时间,除此以外,最好还是测一测哪个锁的效率高,以决定使用哪种锁机制。
public class TestLock {
static long count2 = 0L;
static AtomicLong count1 = new AtomicLong(0L);
static LongAdder count3 = new LongAdder();
public static void main(String[] args) throws Exception {
Thread[] threads = new Thread[1000];
for(int i=0; i<threads.length; i++) {
threads[i] =
new Thread(()-> {
for(int k=0; k<1000000; k++) count1.incrementAndGet();
});
}
long start = System.currentTimeMillis();
for(Thread t : threads ) t.start();
for (Thread t : threads) t.join();
long end = System.currentTimeMillis();
System.out.println("Atomic: " + count1.get() + " time " + (end-start));
//-----------------------------------------------------------
Object lock = new Object();
for(int i=0; i<threads.length; i++) {
threads[i] =
new Thread(new Runnable() {
@Override
public void run() {
for (int k = 0; k < 100000; k++)
synchronized (lock) {
count2++;
}
}
});
}
start = System.currentTimeMillis();
for(Thread t : threads ) t.start();
for (Thread t : threads) t.join();
end = System.currentTimeMillis();
System.out.println("Sync: " + count2 + " time " + (end-start));
//----------------------------------
for(int i=0; i<threads.length; i++) {
threads[i] =
new Thread(()-> {
for(int k=0; k<100000; k++) count3.increment();
});
}
start = System.currentTimeMillis();
for(Thread t : threads ) t.start();
for (Thread t : threads) t.join();
end = System.currentTimeMillis();
System.out.println("LongAdder: " + count1.longValue() + " time " + (end-start));
}