两个线程输出1A 2B 3C 4D 5E 6F…下面介绍四种实现方式:
LockSupport (最简单方式)
代码:
public class LockSupportDemo1 {
static Thread t1;
static Thread t2;
public static void main(String[] args) {
char[] nums = "123456".toCharArray();
char[] zimos = "ABCDEF".toCharArray();
t1 = new Thread(()->{
for (char c: nums){
System.out.print(c);
//叫醒T2
LockSupport.unpark(t2);
//阻塞T1
LockSupport.park();
}
},"t1");
t2 = new Thread(()->{
for (char c: zimos){
//阻塞T2
LockSupport.park();
System.out.print(c);
//叫醒T1
LockSupport.unpark(t1);
}
},"t2");
t1.start();;
t2.start();
}
}
wait notify方式
public class SyncWaitNotifyDemo1 {
public static void main(String[] args) {
final Object object = new Object();
//保证现场执行顺序
CountDownLatch countDownLatch = new CountDownLatch(1);
char[] nums = "123456".toCharArray();
char[] zimos = "ABCDEF".toCharArray();
new Thread(()->{
try {
//该线程阻塞
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
for (char c : zimos){
System.out.print(c);
try {
object.notify();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
object.notify();
}
},"t2").start();
new Thread(()->{
synchronized (object){
for (char c : nums){
System.out.print(c);
//叫醒上面的线程
countDownLatch.countDown();
try {
object.notify();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
object.notify();
}
},"t1").start();
}
}
说明:
wait() 将线程加入到等到队列,notify()将在等待队列中随机挑选一个线程执行。
notify不能叫醒指定的线程,只能随机挑选,notifyAll() 叫醒所有等待线程,大家公抢这把锁
Lock Condition方式
public class ReentrantLockDemo3 {
public static void main(String[] args) {
char[] nums = "123456".toCharArray();
char[] zimos = "ABCDEF".toCharArray();
Lock lock = new ReentrantLock();
//理解为队列
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
new Thread(()->{
try{
lock.lock();
for (char c : nums){
System.out.print(c);
//叫醒对方
condition2.signal();
condition1.await();
}
condition2.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t1").start();
new Thread(()->{
try{
lock.lock();
for (char c : zimos){
System.out.print(c);
//叫醒对方
condition1.signal();
condition2.await();
}
condition1.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t2").start();
}
}
说明:
这里Condition翻译是条件,可以理解为队列,每个线程对应一个Condition。使用signal()唤醒指定线程,await()让指定线程阻塞。
notify不能叫醒指定的线程,使用Lock Condition可以叫醒指定的线程。
TransferQueue(同步队列)方式
public class TransferQueueDemo1 {
public static void main(String[] args) {
char[] nums = "123456".toCharArray();
char[] zimos = "ABCDEF".toCharArray();
TransferQueue<Character> transferQueue = new LinkedTransferQueue<Character>();
new Thread(()->{
try{
for (char c : nums){
//take获取队列数据,阻塞
System.out.print(transferQueue.take());
//把当前字符装机队列中 阻塞
transferQueue.transfer(c);
}
}catch (InterruptedException e){
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try{
for (char c : zimos){
transferQueue.transfer(c);
System.out.print(transferQueue.take());
}
}catch (InterruptedException e){
e.printStackTrace();
}
},"t2").start();
}
}
说明:
TransferQueue使用场景在自定义线程池中比较多。它的原理如下图:
transfer()将一个元素添加到队列中,它是一个阻塞方法,直到被另一个线程消费。
take()方法 也是一个阻塞方法,获取一个元素
所以:TransferQueue队列是一个“手拉手队列”,队列中的长度为0。