1.Lock概述
1.1 java.util.locks.Lock
1.2 Lock接口解释
JDK.5后出现
- void lock() 获取锁
- void unlock() 释放锁
- void lockInterruptibly() 加锁过程中进行抢占锁的时候发生中断 ,并抛出异常
- boolean tryLock() 非阻塞的获取锁
1.2 实现类
- ReentrantLock 可重入锁
public class ReentrantLock implements Lock, java.io.Serializable {
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
- ReentrantReadWriteLock 可重入读写锁(可以排他和共享)
2.Lock使用
2.1 代码示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockSequence {
private int value;
Lock lock = new ReentrantLock();
Lock lock1 = new ReentrantLock();//可以创建多把锁,这样可以让释放和锁的时候更灵活
/**
* 如果每个线程单独锁,还是有线程安全性问题
* @return
*/
public int getNext_1() {
Lock lock1 = new ReentrantLock();//如果这么写是每次都生成一个锁,而应该多线程用同一把锁.
lock1.lock();
value = value ++;
lock1.unlock();//可以讲锁放在finnaly代码块中,可以在发生异常时保证锁的释放.
return value;
}
public int getNext() {
lock.lock();
value = value ++;
lock.unlock();//可以讲锁放在finnaly代码块中,可以在发生异常时保证锁的释放.
return value;
}
public static void main(String[] args) {
LockSequence s = new LockSequence();
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
1.3 Lock总结
- 使用Lock可以方便的实现公平性
- 非阻塞的获取锁 tryLock
- 能被中断的获取锁 lockInterruptibly
- 超时获取锁 在指定的时间类获取锁
1.3 常见线程安全处理方式总结
- Synchronized 不需要显示地获取和释放锁,简单
- Volatile 保证可见性,不保证原子性
- Lock 需要显示地获取和释放锁,繁琐能让代码更灵活,Lock是接口,可以根据需要使用它的实现类.可以简单理解Lock对Synchronied进行的包装,更为强大.
2. 自定义锁(实现Lock)
源码
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class MyLock implements Lock {
private boolean isLocked = false;
private Thread lockBy = null;
private int lockCount = 0;
@Override
public synchronized void lock() {
// ...
Thread currentThread = Thread.currentThread(); // Thread-0
while (isLocked && currentThread != lockBy)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
isLocked = true;
lockBy = currentThread;
lockCount ++; // 1 2
}
@Override
public synchronized void unlock() {
if(lockBy == Thread.currentThread()) {
lockCount --; // 1 0
if(lockCount == 0) {
notify();
isLocked = false;
}
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
}
public class MyLockSequence {
private MyLock lock = new MyLock();
private int value;
public int getNext() {
lock.lock();
value++;
lock.unlock();
return value;
}
public static void main(String[] args) {
MyLockSequence s = new MyLockSequence();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
测试锁的重入
重入锁不能通过Jconsole检查出来
*/
public class MyLockDemo {
//Lock lock = new ReentrantLock();
MyLock lock = new MyLock();//自定义锁
public void a() {
lock.lock();
System.out.println("a");
b();
lock.unlock();
}
public void b() {
lock.lock();
System.out.println("b");
c();
lock.unlock();
}
public void c() {
lock.lock();
System.out.println("c");
lock.unlock();
}
public static void main(String[] args) {
MyLockDemo d = new MyLockDemo();
new Thread(new Runnable() {
@Override
public void run() {
d.a();
}
}).start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// d.b();
// }
// }).start();
}
}
核心说明:
- 通过wait和notify来控制线程状态
- 通过lockBy来和当前的线程对比是否为一个线程来控制重入,及重入计数