線程交替打印的幾種實現方式
- synchronized提供的wait、notify
- LockSupport的park、unpark
- ReentrantLock和condition
- 基於cas機制實現線程交替打印
- TransferQueue實現
synchronized提供的wait、notify
/**
* @author yanyapan
*/
public class WaitNotifyToPrint {
public static void main(String[] args) {
final Object object = new Object();
char[] a1 = "1234567".toCharArray();
char[] a2 = "ABCDEFG".toCharArray();
new Thread(() -> {
synchronized (object){
for(char c : a1){
System.out.print(c);
try{
object.notify();
object.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
object.notify();//避免有線程未被喚醒
}
},"t1").start();
new Thread(() -> {
synchronized (object){
for(char c : a2){
System.out.print(c);
try{
object.notify();
object.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
object.notify();//避免有線程未被喚醒
}
},"t2").start();
}
}
LockSupport的park、unpark
/**
* @author yanyapan
*/
public class LockSupportToPrint {
private static Thread t1;
private static Thread t2;
public static void main(String[] args) {
char[] a1 = "1234567".toCharArray();
char[] a2 = "ABCDEFG".toCharArray();
t1 = new Thread(() -> {
for(char c : a1){
System.out.print(c);
LockSupport.unpark(t2);//釋放t2線程 設置鎖標志位
LockSupport.park();//阻塞當前線程
}
},"t1");
t2 = new Thread(() -> {
for(char c : a2){
LockSupport.park();//阻塞當前線程
System.out.print(c);
LockSupport.unpark(t1);//釋放t1線程
}
},"t2");
t1.start();
t2.start();
}
}
ReentrantLock和condition
/**
* @author yanyapan
*/
public class LockConditionToPrint {
public static void main(String[] args) {
char[] a1 = "1234567".toCharArray();
char[] a2 = "ABCDEFG".toCharArray();
Lock lock = new ReentrantLock();//鎖
Condition t1 = lock.newCondition();//t1隊列
Condition t2 = lock.newCondition();//t2隊列
new Thread(() ->{
try{
lock.lock();
for(char c : a1){
System.out.print(c);
t2.signal();//喚醒t2隊列中等待的線程
t1.await();//進入t1隊列自旋等待
}
t1.signal();//避免有線程未被喚醒
t2.signal();//避免有線程未被喚醒
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t1").start();
new Thread(() ->{
try{
lock.lock();
for(char c : a2){
System.out.print(c);
t1.signal();//喚醒t1隊列中等待的線程
t2.await();//進入t2隊列自旋等待
}
t1.signal();//避免有線程未被喚醒
t2.signal();//避免有線程未被喚醒
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t2").start();
}
}
基於cas機制實現線程交替打印
/**
* @author yanyapan
*/
public class CasToPrint {
enum ReadyToRun{
T1,T2
}
private static volatile ReadyToRun readyToRun = ReadyToRun.T1;
public static void main(String[] args) {
char[] a1 = "1234567".toCharArray();
char[] a2 = "ABCDEFG".toCharArray();
new Thread(() ->{
for(char c : a1){
while (readyToRun != ReadyToRun.T1){}//cas自旋
System.out.print(c);
readyToRun = ReadyToRun.T2;//線程可見性
}
},"t1").start();
new Thread(() ->{
for(char c : a2){
while (readyToRun != ReadyToRun.T2){}//cas自旋
System.out.print(c);
readyToRun = ReadyToRun.T1;//線程可見性
}
},"t2").start();
}
}
TransferQueue實現
/**
* @author yanyapan
*/
public class TransferQueueToPrint {
public static void main(String[] args) {
char[] a1 = "1234567".toCharArray();
char[] a2 = "ABCDEFG".toCharArray();
TransferQueue<Character> queue = new LinkedTransferQueue<>();
new Thread(() ->{
try{
for(char c : a1){
System.out.print(queue.take());
queue.transfer(c);
}
}catch (InterruptedException e){
e.printStackTrace();
}
},"t1").start();
new Thread(() ->{
try{
for(char c : a2){
queue.transfer(c);
System.out.print(queue.take());
}
}catch (InterruptedException e){
e.printStackTrace();
}
},"t2").start();
}
}
總結:
- 需要對jdk底層有深刻的理解,如aqs、synchronized的鎖升級過程、cas機制(jdk中atomic包中大量使用)
- 對jdk中提供的並發數據結構學習掌握
- 理解原理才能寫出對的代碼