java synchronized知识点
synchronized相信学过java并发编程的小伙伴一定不会陌生,synchronized用来控制中线程的同步。
线程安全性:当多个线程同时访问一个类的(对象或者方法),这个类总是表现出正确的行为,则称这个类是线程安全的。
- synchronized的含义
1.互斥性
synchronized用来修饰方法,代码块。
修饰普通成员方法时,取得的对象锁是调用该方法的对象。
修饰静态方法时,取得的对象锁是该类的class对象(存在于方jvm的方法区,只有一个)
修饰代码块的时,对象锁需要开发者自行指定。注意:该对象一定要为共享的,不然线程不安全。
2.内存可见性
synchronzied除了互斥的含义之外,还有可见性的含义。 - synchronized的特性
1.可重入性
重入的一种实现方法:为每一个锁关联一个计数值和一个所有者线程。当计数值为0的时候代表该锁不被任何线程持有。当一个线程请求一个未被持有的锁时,JVM将记下锁的持有者,并将计数值加一。当同一个线程再次获取这个锁的时候,计数值递增,当线程退出同步代码块的时候,计数器递减。当为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关键字来保证线程安全性的时候,将会使线程串行化调用方法或者执行代码块。这也就是一些同步类容器例如vector、hashtable效率不高的原因。
java ReentrantLock知识点
- ReentrantLock的含义
1.ReentrantLock与synchronized不同的地方在于它是一种显示锁,需要手动的lock,unlock,它有自己的condition
2.ReentrantLock也是一种悲观锁
很多人认为ReentrantLock和synchronized比较,前者性能要比后者性能高很多,其实java1.8以后对synchronized性能进行了优化,使其和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();
}
}
运行结果:
从运行结果可以看出,ReentrantLock性能比Synchronized好一点,但也好不太多。(运行环境:JDK1.8)
ReentrantLock之所以比synchronized好的地方在于不是它的性能,而是它的多condition,这是synchronized不能比较的。例如ArrayBlockingQueue中就是用的ReentrantLock,里面有两个condition
总结:并不是所有的地方的都适合用ReentrantLock,具体使用什么要根据生产环境确定。