筑基初期(lock等待锁)
- concurrent是jdk1.5后的包,避免synchronized的出现而设计出来的一种锁机制。
- ReentrantLock 重入锁,在一个对象上加一个标记信息,这个标记信息代表锁机制。
public class Test_01 {
Lock lock = new ReentrantLock();
void m1() {
try {
lock.lock(); // 加锁
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 解锁
}
}
void m2() {
lock.lock();
System.out.println("m2() method");
lock.unlock();
}
public static void main(String[] args) {
final Test_01 t = new Test_01();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
}).start();
}
}
筑基中期(tryLock尝试锁)
尝试锁有阻塞和非阻塞两种
public class Test_02 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock();
for(int i = 0; i < 10; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
void m2(){
boolean isLocked = false;
try{
// 尝试锁, 如果有锁,无法获取锁标记,返回false。
// 非阻塞,如果获取锁标记,返回true
// isLocked = lock.tryLock();
// 阻塞尝试锁,阻塞参数代表的时长,尝试获取锁标记。
// 如果超时,不等待。直接返回。
isLocked = lock.tryLock(5, TimeUnit.SECONDS);
if(isLocked){
System.out.println("m2() method synchronized");
}else{
System.out.println("m2() method unsynchronized");
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(isLocked){
// 尝试锁在解除锁标记的时候,一定要判断是否获取到锁标记。
// 如果当前线程没有获取到锁标记,会抛出异常。
lock.unlock();
}
}
}
public static void main(String[] args) {
final Test_02 t = new Test_02();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
}).start();
}
}
筑基后期(lockInterruptibly可打断锁)
- 阻塞状态有3种: 包括普通阻塞(不释放锁),等待队列(释放锁),锁池队列。
- 普通阻塞: sleep(10000), 可以被打断。调用thread.interrupt()方法,可以打断阻塞状态,抛出异常。
- 等待队列: wait()方法被调用,也是一种阻塞状态,只能由notify唤醒。无法打断。
- 锁池队列: 执行过程中,遇到同步代码,无法获取锁标记。不是所有的锁池队列都可被打断。
- 使用ReentrantLock的lock方法,获取锁标记的时候,如果需要阻塞等待锁标记,无法被打断。
- 使用ReentrantLock的lockInterruptibly方法,获取锁标记的时候,如果需要阻塞等待,可以被打断。
- 可打断锁意义:软件锁死了,无响应,去去任务管理器结束任务
public class Test_03 {
Lock lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 5; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
void m2() {
try {
// 线程执行到这里,本来是不能获得锁标记的,要进入等待队列的。
// 当通过调用当前线程的interrupt(),通过打断当前线程,抛出异常,使线程被唤醒,阻塞结束
lock.lockInterruptibly(); // 可尝试打断的,阻塞等待锁。可以被其他的线程打断阻塞状态
System.out.println("m2() method");
} catch (InterruptedException e) {
// 被打断的异常,被打断与唤醒、阻塞结束都是不一样的
// sleep任何一个线程都可以把他打断,强行唤醒
// 如果是lock不可被打断的
// 如果是lockInterruptibly,阻塞等待这把锁,类似sleep,可以通过interrupt()打断
System.out.println("m2() method interrupted");
} finally {
try {
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final Test_03 t = new Test_03();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
});
t2.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 不调用interrupt()方法,t2最后可以获得锁,继续执行
t2.interrupt();// 打断t2线程,锁的位置会抛出异常。
}
}
筑基圆满(公平锁)
- 在cpu和os中本身线程竞争锁标记是不公平的,不考虑线程的等待时间的。
- 运用在轮询的场景,如打牌。
- 需要效果一部分的cpu资源计算等待的时间,性能有所降低。要仅能少用,并发量在10之内。
public class Test_04 {
public static void main(String[] args) {
TestReentrantlock t = new TestReentrantlock();
//TestSync t = new TestSync();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
}
}
class TestReentrantlock extends Thread {
// 定义一个公平锁
private static ReentrantLock lock = new ReentrantLock(true);
public void run() {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " get lock");
} finally {
lock.unlock();
}
}
}
}
class TestSync extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
//不公平的
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " get lock in TestSync");
}
}
}
}