在java基础-线程状态分析中,LockSupport.park()会使线程进入waiting状态,那么这个park方法是啥,查看源码发现其底层还是调用native方法(Unsafe.park()),此文只讲述park用法,cpp底层代码分析吃力。。。
根据Lock文档描述,每个线程有个许可,当获取不到线程许可的时候,线程是不可用的,即处于waiting或者(timed_waiting状态);当执行park后,只有执行unpark或者线程interrupt或者虚假唤醒
park许可只有0和大于0 。当线程的许可大于0,park不堵塞;unpark不叠加,当执行unpark会使许可大于0。
1. 2次park,不unpark,线程waiting
public class LockPark {
private static int num = 0;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (num < 2) {
System.out.println(Thread.currentThread().getName() + ":park begin");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park first");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
}
});
thread.start();
// LockSupport.unpark(thread);
// System.out.println(thread.getName() + ":unpark first");
num++;
}
}
2. 2次park,1次unpark
public class LockPark {
private static int num = 0;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (num < 2) {
System.out.println(Thread.currentThread().getName() + ":park begin");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park first");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
}
});
thread.start();
LockSupport.unpark(thread);
System.out.println(thread.getName() + ":unpark first");
num++;
}
}
3. 2次park,2次unpark
public class LockPark {
private static int num = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (num < 2) {
System.out.println(Thread.currentThread().getName() + ":park begin");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park first");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
}
});
thread.start();
LockSupport.unpark(thread);
System.out.println(thread.getName() + ":unpark first");
num++;
//演示明显
Thread.sleep(100);
LockSupport.unpark(thread);
num++;
System.out.println(thread.getName() + ":unpark second");
}
}
由 1 2 3示例可知 unpark每次授权一个,park就会唤醒
4. 2次unpark,2次park,执行顺序颠倒,可证明unpark不累积
public class LockPark {
private static int num = 2;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
if (num < 2) {
System.out.println(Thread.currentThread().getName() + ":park begin");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park first");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
}
}
});
thread.start();
LockSupport.unpark(thread);
System.out.println(thread.getName() + ":unpark first");
LockSupport.unpark(thread);
System.out.println(thread.getName() + ":unpark second");
num = 0;
while (true){
}
}
}
5. 2次park,1次中断
public class LockPark {
private static int num = 0;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true) {
if (num < 2) {
System.out.println(Thread.currentThread().getName() + ":park begin");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park first");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
System.out.println(Thread.currentThread().getName() + ":interrupt first,状态是:"+Thread.currentThread().isInterrupted());
try {
sleep(1000000);
} catch (InterruptedException e) {
//抛出异常后,会将状态置位为false
}
System.out.println(Thread.currentThread().getName() + ":interrupt second,状态是:"+Thread.currentThread().isInterrupted());
//
LockSupport.park();
System.out.println(Thread.currentThread().getName() + ":park second");
}
}
});
thread.start();
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
while (true){
}
}
}
一. Reentrantlock初步使用
LockSupport.park在AQS中使用,ReentrantLock会使用AQS,此文先分析ReentrantLock,AQS后面再分析,常用的两个锁有Reentrantlock(互斥锁)和ReentrantReadWriteLock(读共享,写互斥,读写互斥
1. Reentrantlock互斥
public class ReentrantlockOne {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Thread threadOne = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
threadOne.start();
Thread threadTwo = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
threadTwo.start();
Thread.sleep(100);
System.out.println(threadOne.getName()+ "状态是:" + threadOne.getState());
System.out.println(threadTwo.getName() + "状态是:" + threadTwo.getState());
}
}
2. ReentrantReadWriteLock读共享
public class ReentrantReadWriteLockOne {
public static void main(String[] args) throws InterruptedException {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
Thread threadOne = new Thread(() -> {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
});
threadOne.start();
Thread threadTwo = new Thread(() -> {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
});
threadTwo.start();
Thread.sleep(100);
System.out.println(threadOne.getName() + "状态是:" + threadOne.getState());
System.out.println(threadTwo.getName() + "状态是:" + threadTwo.getState());
}
}
3. ReentrantReadWriteLock写互斥
public class ReentrantReadWriteLockOne {
public static void main(String[] args) throws InterruptedException {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
Thread threadOne = new Thread(() -> {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
});
threadOne.start();
Thread threadTwo = new Thread(() -> {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
});
threadTwo.start();
Thread.sleep(100);
System.out.println(threadOne.getName() + "状态是:" + threadOne.getState());
System.out.println(threadTwo.getName() + "状态是:" + threadTwo.getState());
}
}
4. ReentrantReadWriteLock 读写互斥
public class ReentrantReadWriteLockOne {
public static void main(String[] args) throws InterruptedException {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
Thread threadOne = new Thread(() -> {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
});
threadOne.start();
Thread.sleep(100);
Thread threadTwo = new Thread(() -> {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到线程");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
});
threadTwo.start();
//此处睡眠是为了能获取waiting状态
Thread.sleep(100);
System.out.println(threadOne.getName() + "写锁状态是:" + threadOne.getState());
System.out.println(threadTwo.getName() + "读锁状态是:" + threadTwo.getState());
}
}
二. Reentrantlock实现生产者消费者
使用condition和await实现
public class ConsumerAndProducer {
private static int num = 6;
private static List<Integer> list = new ArrayList<>();
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition producer = lock.newCondition();
Condition consumer = lock.newCondition();
//生产者组
for (int i = 0; i < 5; i++) {
new Thread(() -> {
//死循环一直生产
while (true) {
lock.lock();
try {
while (list.size() == num) {
System.out.println(Thread.currentThread().getName() + "生产已经满了:" + list.size());
producer.await();
}
int object = (int) (Math.random() * 6);
System.out.println(Thread.currentThread().getName() + "生产:" + object);
list.add(object);
consumer.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
}
//消费者组
for (int i = 0; i < 5; i++) {
new Thread(() -> {
while (true) {
lock.lock();
try {
while (list.size() == 0) {
System.out.println(Thread.currentThread().getName() + "消费已经空了:" + list.size());
consumer.await();
}
int object = list.get(0);
list.remove(0);
System.out.println(Thread.currentThread().getName() + "消费:" + object);
producer.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
}
}
}