重入锁——可替代synchronized
麻烦的是需要手动解锁,一般在finally里面释放锁
它所指的重入锁仅针对一个线程。
package test;
import java.util.concurrent.locks.ReentrantLock;
public class ReenterLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();
try {
i++;
} finally {
lock.unlock();
}
}
}
public static void main(String args[]) throws InterruptedException {
ReenterLock tl = new ReenterLock();
Thread t1 = new Thread(tl);
Thread t2 = new Thread(tl);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
重入锁的高级功能。
1.中断响应
区别与synchronized关键字实现的同步,如果线程在等待锁,要么得到锁得以继续执行,要么就是一直等待。而重入锁不一样,可以根据需要取消对锁的等待或申请。
package caninterruptedReentrantLock;
import java.util.concurrent.locks.ReentrantLock;
public class IntLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public IntLock(int lock) {
this.lock = lock;
}
@Override
public void run() {
try {
if (lock == 1) {
lock1.lockInterruptibly();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
lock2.lockInterruptibly();
} else {
lock2.lockInterruptibly();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
lock1.lockInterruptibly();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock1.isHeldByCurrentThread())
lock1.unlock();
if (lock2.isHeldByCurrentThread())
lock2.unlock();
System.out.println(Thread.currentThread().getId() + ":线程退出");
}
}
public static void main(String args[]) throws InterruptedException {
IntLock r1 = new IntLock(1);
IntLock r2 = new IntLock(2);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt();
}
}
2.锁申请等待时间
除了响应外部的中断等待通知外,避免死锁的另外一个方法就是限时等待
package TimeReentrantLock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TimeLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
Thread.sleep(6000);
} else {
System.out.println("get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread())
lock.unlock();
}
}
public static void main(String[] args) {
TimeLock t = new TimeLock();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
}
}
3.公平锁
大多数情况下,锁的申请都是非公平的,也就是就算你是等待申请时间最长的线程,可能当有锁释放时,你也不一定能获得这把锁。而公平锁意味着会按照时间的先后顺序,保证先到者先得,后到者后得。而重入锁ReentrantLock通过传入参数fair可以实现公平锁。
重入锁与Condition
类似于Object.wait()方法和Object.notify()方法与synchronized联合使用时,Condition是与重入锁相关联的,通过lock接口的Condition new Condition()方法可以实现二者的绑定。
package ReentrantLockCondition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockCondition implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
@Override
public void run() {
// TODO Auto-generated method stub
try {
lock.lock();
condition.await();
System.out.println("Thread is going on");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String args[]) throws InterruptedException {
ReentrantLockCondition t = new ReentrantLockCondition();
Thread t1 = new Thread(t);
t1.start();
Thread.sleep(2000);
lock.lock();
condition.signal();
lock.unlock();
}
}
信号量semaphore
信号量为多线程协作提供了更加强大的控制方法,synchronized与重入锁都要求一次只允许一个线程访问一个资源。而信号量可以指定多个线程同时访问某一个资源。必须指定信号量的准入数。
package SamapDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemapDemo implements Runnable {
final Semaphore semp=new Semaphore(5);
@Override
public void run() {
try{
semp.acquire();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId()+":done!");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
semp.release();
}
}
public static void main(String[] args) {
ExecutorService exec=Executors.newFixedThreadPool(20);
final SemapDemo demo=new SemapDemo();
for(int i=0;i<20;i++){
exec.submit(demo);
}
}
}
ReadWriteLock读写锁
package ReadWriteLockDemo;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private static Lock lock=new ReentrantLock();
private static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
private static Lock readLock=readWriteLock.readLock();
private static Lock writeLock=readWriteLock.writeLock();
private int value;
public Object handleRead(Lock lock) throws InterruptedException{
try{
lock.lock();//模拟读操作
Thread.sleep(1000);//读操作耗时越久,读写锁的优势体现得越明显
return value;
}
finally{
lock.unlock();
}
}
public void handleWrite(Lock lock,int index) throws InterruptedException{
try{
lock.lock();
Thread.sleep(1000);
value=index;
}finally{
lock.unlock();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final ReadWriteLockDemo demo=new ReadWriteLockDemo();
Runnable readRunnable=new Runnable() {
@Override
public void run() {
try{
demo.handleRead(readLock);
}
catch(InterruptedException e){
e.printStackTrace();
}
}
};
Runnable writeRunnable=new Runnable() {
@Override
public void run() {
try{
demo.handleWrite(writeLock, new Random().nextInt());
}
catch(InterruptedException e){
e.printStackTrace();
}
}
};
for(int i=0;i<18;i++){
new Thread(readRunnable).start();
}
for(int i=18;i<20;i++){
new Thread(writeRunnable).start();
}
}
}