Java处理高并发,大数据,多线程,分布式这些都会产生一个严重的后果,如何保证线程安全和数据的一致性成为重中之重。为了实现这点就不得不使用到了锁机制,java提供了4种常见的锁机制,当然其中Synchronized是最常见和常用的,jdk的很多线程安全类都用Synchronized实现,关于Synchronized可以见之前的文章《java同步锁(synchronized)机制再总结》,但是没有涉及到Synchronized的锁升级机制问题。
Lock(ReentrantLock)
例子
private static Lock lock = newReentrantLock();
public void fun()
{
lock.lock();
System.out.println(Thread.currentThread().getName());
System.out.println(servId+”object”+index+”funstart”);
System.out.println(servId+”object”+index+”funend”);
lock.unlock();
}
多线程调用fun时会串行化保证线程安全。注意lock为静态成员,是的,就是这么简单,你就能使用比较高大上的lock机制了,ReentrantLock有两个构造方法,ReentrantLock()和ReentrantLock(boolean fair),前者是默认非公平锁,后者参数为true的话是公平锁,什么叫公平锁,很简单就是先被阻塞排队等锁资源的线程优先拿到锁资源,非公平就是随机,不保证先到先得。如何实现先到先得,很简单把等待的线程加入队列容器,而队列容器就是典型的先到先得特性。
底层实现:
额,比较复杂,我还没有花时间去深入研究,但是通过资料可以最终知道是使用了CAS机制,这个机制某种程度而言是几乎所有锁机制的底层实现,是通过对其他cpu的硬件阻塞实现命令执行的串行化。以下是网上摘录的一段话:
现在的处理器都支持多重处理,当然也包含多个处理器共享外围设备和内存,同时,加强了指令集以支持一些多处理的特殊需求。特别是几乎所有的处理器都可以将其他处理器阻塞以便更新共享变量。
说白了就算获得锁的线程所执行代码的cpu把其他cpu都阻塞了,自己独自使用整个主机的一个公共变量,cpu都被冻结了,理所当然其他线程就无法使用cpu执行自己的代码,用这样硬件的控制实现了最底层的串行化,以达成线程安全的目的。
Semaphore
信号量,多线程共享的公共变量,跟公共内存一样,在C++中好像还能实现多进程共享,但是java不知能否支持,当然多线程是可以共享无疑。
例子
private static Semaphore semaphore=newSemaphore(1,true);
public void fun(int index,long servId)
{
try{
semaphore.acquire();
System.out.println(Thread.currentThread().getName());
System.out.println(servId+”object”+index+”funstart”);
System.out.println(servId+”object”+index+”funend”);
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}finally{
semaphore.release();
}
}
new Semaphore(1,true);的意思是信号量初始值是1,true表示保证先进先出的公平性,跟ReentrantLock类似,每执行semaphore.acquire()一次,信号量减一,semaphore.release()执行一次信号量加一。但信号量为0时,其他线程无法进入该段代码。阻塞等待。
底层实现:
一样,底层实现依靠CAS机制。
Atomic
这是一个系列,包括AtomicLong,AtomicInteger等,主要是用来定义计数器用的,并且保证该计数器的线程安全,怎么讲,也就是我们普通的i++或++i这类的计数器常用自增方式其实是非原子操作,分成两步,第一步a=i+1,第二步i=a,所以要实现计数器的线程安全就选用Atomic系列的类,而不用自己花时间去写加锁代码,并且Atomic系列的效率远远高于自己写的同步代码。
用法:
private static AtomicLong atomicLong=newAtomicLong(0);
atomicLong.incrementAndGet();
atomicLong.decrementAndGet();
底层实现:
一样,底层实现依靠CAS机制。
Synchronized
具体信息和例子可以见之前的文章《java同步锁(synchronized)机制再总结》
底层实现:
还是CAS机制?说是也对说不是也对,因为涉及到所谓的锁升级的问题,只有重型锁是靠CAS机制,具体升级流程:无锁状态->偏向锁->轻量级锁->重量级锁,为什么这样实现是不想在并发不高,线程竞争不激烈的情况下少调用硬件锁这种效率比较低,对整个程序性能影响较大的机制。具体升级条件以后再分析。