java synchronized知識點
synchronized相信學過java并發(fā)編程的小伙伴一定不會陌生,synchronized用來控制中線程的同步溜宽。
線程安全性:當多個線程同時訪問一個類的(對象或者方法)实苞,這個類總是表現(xiàn)出正確的行為豺撑,則稱這個類是線程安全的。
- synchronized的含義
1.互斥性
synchronized用來修飾方法黔牵,代碼塊聪轿。
修飾普通成員方法時,取得的對象鎖是調(diào)用該方法的對象猾浦。
修飾靜態(tài)方法時陆错,取得的對象鎖是該類的class對象(存在于方jvm的方法區(qū)灯抛,只有一個)
修飾代碼塊的時,對象鎖需要開發(fā)者自行指定音瓷。注意:該對象一定要為共享的对嚼,不然線程不安全。
2.內(nèi)存可見性
synchronzied除了互斥的含義之外绳慎,還有可見性的含義纵竖。 - synchronized的特性
1.可重入性
重入的一種實現(xiàn)方法:為每一個鎖關(guān)聯(lián)一個計數(shù)值和一個所有者線程。當計數(shù)值為0的時候代表該鎖不被任何線程持有杏愤。當一個線程請求一個未被持有的鎖時靡砌,JVM將記下鎖的持有者,并將計數(shù)值加一珊楼。當同一個線程再次獲取這個鎖的時候通殃,計數(shù)值遞增,當線程退出同步代碼塊的時候亥曹,計數(shù)器遞減邓了。當為0的時候,這個鎖被釋放媳瞪。
第一個例子:
public class UseSynchronized {
public synchronized void method1(){
System.out.println("進入方法1");
method2();
}
public synchronized void method2(){
System.out.println("進入方法2");
method3();
}
public synchronized void method3(){
System.out.println("進入方法3");
}
public static void main(String[] args) {
final UseSynchronized us=new UseSynchronized();
us.method1();
}
}
第二個例子:
java
public class UseSynchronized {
private class A{
public synchronized void test(){
System.out.println("這是父類的方法");
}
}
class B extends A{
public synchronized void test(){
System.out.println("這是子類的方法");
super.test();
}
}
public static void main(String[] args) {
B b=new UseSynchronized().new B();
b.test();
}
}
```
2.悲觀鎖骗炉、獨占鎖
使用synchronized關(guān)鍵字來保證線程安全性的時候,將會使線程串行化調(diào)用方法或者執(zhí)行代碼塊蛇受。這也就是一些同步類容器例如vector句葵、hashtable效率不高的原因。
java ReentrantLock知識點
- ReentrantLock的含義
1.ReentrantLock與synchronized不同的地方在于它是一種顯示鎖兢仰,需要手動的lock乍丈,unlock,它有自己的condition
2.ReentrantLock也是一種悲觀鎖
很多人認為ReentrantLock和synchronized比較把将,前者性能要比后者性能高很多轻专,其實java1.8以后對synchronized性能進行了優(yōu)化,使其和ReentrantLock的性能相差不多察蹲。
package org.lock;
import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
abstract class Accumulator{
public static long cycles=50000L;
private static final int N=5;
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{
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{
@Override
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{
@Override
public void run() {
for(long i=0;i<cycles;i++){
value=read();
}
try {
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public void timeTest(){
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;
System.out.println(id+"----"+duration);
}
public static void report(Accumulator acc1,Accumulator acc2){
System.out.println(acc1.id+"/"+acc2.id+"="+(double)acc1.duration/(double)acc2.duration);
}
}
class BaseLine extends Accumulator{
{
id="BaseLine";
}
@Override
public void accumulate() {
value+=preLoaded[index++];
if(index>=SIZE){
index=0;
}
}
@Override
public long read() {
return value;
}
}
class SynchronizedTest extends Accumulator{
{
id="synchronized";
}
@Override
public synchronized void accumulate() {
value+=preLoaded[index++];
if(index>=SIZE){
index=0;
}
}
@Override
public synchronized long read() {
return value;
}
}
class LockTest extends Accumulator{
{
id="Lock";
}
private Lock lock=new ReentrantLock();
@Override
public void accumulate() {
lock.lock();
try{
value+=preLoaded[index++];
if(index>=SIZE){
index=0;
}
}finally{
lock.unlock();
}
}
@Override
public long read() {
lock.lock();
try{
return value;
}finally{
lock.unlock();
}
}
}
public class SynchronizationComparisons {
static SynchronizedTest synch=new SynchronizedTest();
static LockTest lock=new LockTest();
static void test(){
System.out.println("==========================");
System.out.println("Cyccle"+" "+Accumulator.cycles);
synch.timeTest();
lock.timeTest();
Accumulator.report(synch, lock);
}
public static void main(String[] args) {
int iterations=5;
if(args.length>0){
iterations=new Integer(args[0]);
}
System.out.println("Warmup");
for(int i=0;i<iterations;i++){
test();
Accumulator.cycles*=2;
}
Accumulator.exec.shutdown();
}
}
運行結(jié)果:
從運行結(jié)果可以看出,ReentrantLock性能比Synchronized好一點请垛,但也好不太多。(運行環(huán)境:JDK1.8)
ReentrantLock之所以比synchronized好的地方在于不是它的性能洽议,而是它的多condition宗收,這是synchronized不能比較的。例如ArrayBlockingQueue中就是用的ReentrantLock亚兄,里面有兩個condition
總結(jié):并不是所有的地方的都適合用ReentrantLock,具體使用什么要根據(jù)生產(chǎn)環(huán)境確定混稽。