Synchronized是线程执行完毕以后释放资源,这里我们看不到手动锁住临界区和释放临界区的操作,而重入锁可以做到这一点。
重入锁使用
java.util.concurrent.locks.ReentrantLock
先放代码帮助理解
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReenterLockCondition implements Runnable {
public static ReentrantLock lock=new ReentrantLock();
static int i=0;
@Override
public void run() {
while (i < 101) {
try{
lock.lock();//第一个进入的线程获得锁,锁住该执行语句一下的代码块
System.out.println(Thread.currentThread().getName()+" "+i);
i++;
}finally {
lock.unlock();//解锁
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLockCondition instance=new ReenterLockCondition();
Thread t1=new Thread(instance,"T1");
Thread t2=new Thread(instance,"T2");
t1.start();
t2.start();
}
}
这里代码很好理解获得lock的线程锁住lock-unlock里面的代码块,执行完以后释放代码块,不过以经验来说下一次获得该锁的仍然是之前持有锁的那个线程几率比较大,我运行了几遍都是第一次进入的是哪个线程后面都是那个线程持有该锁:
此时我们使用的是非公平锁,公平锁的话是按照时间顺序,只要你排队,最后还是可以得到资源的,写公平锁比较简单只需要:
public static ReentrantLock lock=new ReentrantLock(true);
跑出来有交替进行,如果跑一次发现只有一个线程享用资源了不妨多跑几遍,我也是跑了5,6遍才跑出了一个交替进行的,线程的小脾气。
进阶:中断操作,重入锁条件condition
允许多个线程同时访问:信号量Semaphore:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaDemo implements Runnable{
final Semaphore semp=new Semaphore(3,true);//第一个参数指定同时允许几个线程访问,第二参数指定是否公平
static int i=0;
@Override
public void run() {
while (i < 101) {
try{
semp.acquire();//获得准入许可
System.out.println(Thread.currentThread().getId()+" "+i);
i++;
semp.release();//访问资源结束后,释放许可。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
final SemaDemo semaDemo=new SemaDemo();
ExecutorService exec= Executors.newFixedThreadPool(3);
for (int j=0;j<3;j++){
exec.submit(semaDemo);
}
}
}