1.上一篇说到了synchronized的缺陷:
synchronized的缺陷:
1.使用synchronized包住的代码块,只可能有两种状态:顺利执行完毕释放锁,执行发生异常释放锁,不会由于异常导致出现死锁现象
2.如果synchronized包住的代码块中有sleep等操作,比如I/O阻塞,但是其他线程还是需要等待,这样程序的效率就比较低了
3.等待synchronized释放锁的线程会一直等待下去(死心塌地,不到黄河心不死)
由此可见,synchronized并不是最好的锁,是由缺点的。
有如下场景:
对a.txt这个文件,A,B线程都可以进行读写,写操作与写操作会发生冲突,写操作与读操作会发生冲突,但是,读操作与读操作不会发生冲突
就需要有某种锁,可以在读操作与读操作之间,不会发生冲突
这里介绍另外一种可以控制临界资源访问的锁
2.Lock:
Lock接口解决了synchronized的缺陷。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
通过Lock的源码可以知道,lock(),tryLock(),tryLock(long time,Time Unit),lockInterruptiably()是用来获取锁的
lock()方法是平常使用得最多的一个方法,用来获取锁,如果锁已经被其他线程获取,则进行等待,可以说和synchronized没有差别
Lock lock = ...;
lock.lock();
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
/**
* Created by liuyl on 15/11/27.
*/
public class ThreadLock {
private ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
ThreadLock mt = new ThreadLock();
new Thread(){
@Override
public void run() {
mt.insert(this);
}
}.start();
new Thread(){
@Override
public void run() {
mt.insert(this);
}
}.start();
}
public void insert(Thread thread){
//获得锁
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"获得锁");
} catch (Exception e) {
//一定要在这边释放锁
}finally {
System.out.println(Thread.currentThread().getName()+"释放锁");
lock.unlock();
}
}
}
tryLock()是有返回值的,且会立即返回,不会一直等待,如果获取到锁,则返回true,否则返回false
Lock lock = ...;
if(lock.tryLock()) {
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
}else {
//如果不能获取锁,则直接做其他事情
}
tryLock()的示例代码:
public class ThreadLock2 {
private ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
ThreadLock2 mt = new ThreadLock2();
new Thread() {
@Override
public void run() {
mt.insert(this);
}
}.start();
new Thread() {
@Override
public void run() {
mt.insert(this);
}
}.start();
}
public void insert(Thread thread) {
if (lock.tryLock()) {
try {
System.out.println(thread.getName() + "得到了锁");
} catch (Exception e) {
} finally {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName() + "释放了锁");
lock.unlock();
}
} else {
System.out.println(thread.getName() + "获取锁失败");
}
- }
}
lockInterruptibly()当这个方法正在获取锁时,能够响应中断。
public void method() throws InterruptedException {
lock.lockInterruptibly();
try {
//.....
}
finally {
lock.unlock();
}
}
示例代码:
public class ThreadLock3 {
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
ThreadLock3 test = new ThreadLock3();
MyThread thread1 = new MyThread(test);
MyThread thread2 = new MyThread(test);
thread1.start();
thread2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.interrupt();
}
public void insert(Thread thread) throws InterruptedException {
lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
try {
System.out.println(thread.getName() + "得到了锁");
long startTime = System.currentTimeMillis();
for (; ; ) {
if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
break;
// thrad1在这边一直卡住
}
} finally {
System.out.println(Thread.currentThread().getName() + "执行finally");
lock.unlock();
System.out.println(thread.getName() + "释放了锁");
}
}
}
class MyThread extends Thread {
private ThreadLock3 test = null;
public MyThread(ThreadLock3 test) {
this.test = test;
}
@Override
public void run() {
try {
test.insert(Thread.currentThread());
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "被中断");
}
}
}
ReentranReadWriteLock分为readLock()和writeLock()来获取读写锁
public class ReadAndWriteLOck {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ArrayList<Integer> list = new ArrayList<>();
public static void main(String[] args) {
ReadAndWriteLOck mt = new ReadAndWriteLOck();
new Thread(){
@Override
public void run() {
mt.insert(Thread.currentThread());
}
}.start();
new Thread(){
@Override
public void run() {
mt.insert(Thread.currentThread());
}
}.start();
}
public void insert(Thread thread){
lock.readLock().lock();
try {
long start = System.currentTimeMillis();
while(System.currentTimeMillis() - start <= 200) {
System.out.println(thread.getName()+"正在进行读操作");
}
System.out.println(thread.getName()+"读操作完毕");
} finally {
lock.readLock().unlock();
}
}
}
输出结果:
线程0和线程1交替执行
Lock和synchronized的选择:
1.Lock是java内置的一个类,synchronized是关键字
2.Lock必须要使用unlock()方法在finally中释放,如果没有主动释放锁,就有可能导致出现死锁现象,发生异常时不会自动释放,synchronized发生异常时会自动释放
3.Lock在等待获取锁的时候可以响应中断,synchronize则不会
4.Lock可以知道获取锁是否成功
5.Lock有读写锁功能