1、级别不同:
Synchronized是java的一个关键字,用于对所修饰的区域加锁,实现线程同步;
ReenTrantLock是java提供的一个实现加锁的类,也可以实现线程同步。
2、重入锁:
Synchronized和ReentrantLock都是重入锁
3、锁对象:
(1)synchronized:
Synchronized可以修饰方法、代码块等,可以指定锁对象,在修饰方法时,也可以不指定锁对象,当不指定锁对象时,但在修饰代码块时要求指定锁对象;
当修饰静态方法时,如果不指定锁对象,则锁是当前类;
当修饰非静态方法时,如果不指定锁对象,则锁是当前对象实例。
(2)ReentrantLock:
由创建的ReentrantLock对象调用方法实现加锁解锁
4、ReentrantLock的优势:
ReentrantLock用途和synchronized相同,只是ReentrantLock更加灵活
1、ReentrantLock需要使用相应方法进行加锁解锁,使用lock()加锁,使用unlock()解锁,unlock()经常写在finally中;
2、可以使用tryLock()进行尝试获得锁,如果获得锁失败,返回false,获得成功返回true,这使得线程不用在请求锁的时候一直处于等待状态,可以根据是否获得锁,相应地去做下一步的逻辑;
3、ReentrantLock可以设置为公平锁: new ReentrantLock(true);默认为非公平锁 new ReentrantLock(false)或者new ReentrantLock( )结果是一样的;
4、可以使用LockInterruptibly( )控制一直处于等待锁状态的线程,可以将一个一直等待锁对象,但是无法获得锁的线程中断掉。
LockInterruptibly( )使用方法:
场景: 线程1持有锁,线程2一直等待获得锁,为了让线程2不再等待,将线程2中断掉
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockInterruptiblyTest {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("线程1持有锁,不想释放锁");
Thread.sleep(500);
System.out.println("线程1持有锁,不想释放锁");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("线程1释放锁");
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2请求锁,不能获得锁");
try {
lock.lockInterruptibly();
try {
System.out.println("线程2持有锁,不想释放锁");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} catch (InterruptedException e1) {
e1.printStackTrace();
System.out.println("线程2获得锁失败");
}
}
});
thread1.start();
thread2.start();
//在主线程中将等待获得锁对象的线程2中断掉
thread2.interrupt();
}
}
执行结果:
发现:当线程1持有锁,而线程2持续等待锁时,在主线程中 thread2.interruptibly( );将线程2直接中断掉了。