一:java中的锁
java中的锁关键字分为3种:Lock、Synchronized以及volatile。
1 .Lock和Synchronized区别
Lock: 为java中的显示锁,锁的获取和释放可以在不同的
Synchronized:为java中隐石锁,所得获取和释放是在同步代码块的开始结束位置,是java实现同步的最简单的方法。
2.Synchronized和volatile的区别
Synchronized:是java提供一个重量级别的锁,可以保证可见性、原子性等。
volatile:是java5之后对于Synchronized优化的轻锁,可以保证多线程锁的可见性,但是原子性无法保证。
3.为什么不用Synchronized(valatitle)而采用Lock
在上面几节我们谈到了Synchronized/volatitle的使用优化,尽然如此为什么还要用Lock呢?原因就是:前2种锁的加锁/解锁过程是针对读和写的。也就是如果一个方法既有读和写,其中读的频率有99%而写只有1%,Synchronized会将方法加锁导致99%读也会被加锁,而我们读操作是没有改变任何东西,只要读就行。因此Lock是为了消除Synchronized的读操作的加锁/解锁过程的。
二:Lock锁也是一个对象锁
注意Lock也是一个对象锁,这就是说,一个对象一旦拥有多个加锁的方法,他也是同步执行的,代码如下:
1.没有锁的
package Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 验证Lock也是一个对象锁
* @author monxz
*
*/
public class ObjectLock {
/**
* 定义Lock
*/
private Lock lock=new ReentrantLock();
public void methodA() {
//加锁
// lock.lock();
try {
System.out.println("=====A方法开始执行");
for(int i = 0; i < 3 ;i ++){
System.out.println("=====线程执行方法A:"+Thread.currentThread().getName()+",顺序:"+i);
Thread.sleep(1000);
}
System.out.println("=====A方法执行结束");
} catch (Exception e) {
e.printStackTrace();
}finally {
//解锁
// lock.unlock();
}
}
public void methodB() {
//加锁
// lock.lock();
try {
System.out.println("=====B方法开始执行");
for(int i = 0; i < 3 ;i ++){
System.out.println("=====线程执行方法B:"+Thread.currentThread().getName()+",顺序:"+i);
Thread.sleep(1000);
}
System.out.println("=====B方法执行结束");
} catch (Exception e) {
e.printStackTrace();
}finally {
//解锁
// lock.unlock();
}
}
public static void main(String[] args) {
/**
* ta,tb线程执行A,B俩个方法,注意这里ta,tb是同时执行的
*/
ObjectLock lockService = new ObjectLock();
ThreadA ta =new ThreadA(lockService);
ta.setName("ta");
ta.start();
ThreadB tb =new ThreadB(lockService);
tb.setName("tb");
tb.start();
}
}
//定义线程A类
class ThreadA extends Thread{
private ObjectLock lockService;
public ThreadA(ObjectLock ls){
this.lockService = ls;
}
@Override
public void run() {
lockService.methodA();
}
}
//定义线程B类
class ThreadB extends Thread{
private ObjectLock lockService;
public ThreadB(ObjectLock ls){
this.lockService = ls;
}
@Override
public void run() {
lockService.methodB();
}
}
运行结果:注意A,B是同事执行的,没有顺序
2.使用Lock锁
这里只要把上面的A,B方法中的lock.lock()和lock.unlock()注释即是A,B都加锁了。
运行结果:结果与上面比对就很明显了吧。
三:Lock锁的API
1.首先这里先截图出api
2.无锁多线程运行
在无锁的情况下,多线程运行或出现没有顺序,这里上代码:
/**
* 无锁多线程演示
* @author monxz
*
*/
class NoLockTest implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + "线程:执行顺序: "+i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
NoLockTest test =new NoLockTest();
for(int i = 0; i < 5 ; i++){
Thread thread = new Thread(test, "线程"+i);
thread.start();
}
}
运行结果:
3.简单的Lock锁
/**
* 简单的lock演示
* 说明:当前线程获取锁并且在执行方法,其他线程同时也获取锁,获取不到其他线程进入阻塞队列
* @author monxz
*
*/
class onlysimpleLockTest implements Runnable{
Lock lock = new ReentrantLock();
@Override
public void run() {
try {
//加锁
lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "线程:执行顺序: "+i);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
}
public static void main(String[] args) {
onlysimpleLockTest test =new onlysimpleLockTest();
for(int i = 0; i < 5 ; i++){
Thread thread = new Thread(test, "线程"+i);
thread.start();
}
}
运行结果(部分):
4.简单的tryLock()
/**
* 简单的tryLock()演示
* 说明:如果当前线程获取到锁并且执行中,那么其他线程获取不到锁,其他线程死亡
* @author monxz
*
*/
class tryLockTest implements Runnable{
Lock lock = new ReentrantLock();
@Override
public void run() {
if(lock.tryLock()){
try {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "线程:执行顺序: "+i);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}else{
System.out.println("线程"+Thread.currentThread().getName()+"没有获取锁!");
}
}
}
public static void main(String[] args) {
tryLockTest test =new tryLockTest();
for(int i = 0; i < 5 ; i++){
Thread thread = new Thread(test, "线程"+i);
thread.start();
}
}
运行结果:
5.tryLock(Long time timeUtil timeUtil)
/**
* tryLock(time,timePS)添加时间等待
* 说明:多线程中随机一个线程获取当前锁, 如果在当前线程在等待时间结束前没有执行完毕,其他线程全部放弃。如果执行完毕,剩余线程共同执行tryLock();
* 示例:比如100个线程,第1个线程获取锁执行代码在等待时间结束前没有执行完成,其他99个线程放弃死亡。如果执行完毕,剩余的99个随机一个执行,其他98个死亡
* @author monxz
*
*/
class tryLockTimeTest implements Runnable{
Lock lock = new ReentrantLock();
@Override
public void run() {
try {
if(lock.tryLock(1000,TimeUnit.MILLISECONDS)){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "线程:执行顺序: "+i);
Thread.sleep(1000);
}
lock.unlock();
}else{
System.out.println("线程"+Thread.currentThread().getName()+"没有获取锁!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
tryLockTimeTest test =new tryLockTimeTest();
for(int i = 0; i < 5 ; i++){
Thread thread = new Thread(test, "线程"+i);
thread.start();
}
}
}
运行结果:
四:Lock的其他的一些api
getHoldCount() :获取当前锁定(got)的个数
getQueueLength() :获取当前正在等待获取(getting)锁的线程数(Threads)
getWaitQueueLength(Condition) :返回等待(await)与此锁定(got)的Condition相关的个数