一、题目描述
建立三个线程A、B、C,A线程打印10次字母A,B线程打印10次字母B,C线程打印10次字母C,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印
这里参照网上方案,特此整理如下:
1、使用synchronized, wait和notifyAll
2、使用Lock->ReentrantLock 和 state标志
3、使用Lock->ReentrantLock 和Condition(await 、signal、signalAll)
4、使用AtomicInteger
二、synchronized,wait和notifyAll方式
/**
* @author 60055558
* @version 1.0
*/
public class ThreadPrinter01 {
/*使用同步代码块synchronized、wait、notifyAll控制线程执行顺序
*/
public static void main(String[] args) throws Exception{
Object a = new Object();
Object b = new Object();
Object c = new Object();
ThreadPrinter pa = new ThreadPrinter("A",c,a);
ThreadPrinter pb = new ThreadPrinter("B",a,b);
ThreadPrinter pc = new ThreadPrinter("C",b,c);
new Thread(pa).start();
Thread.sleep(10);// 保证初始ABC的启动顺序
new Thread(pb).start();
Thread.sleep(10);
new Thread(pc).start();
Thread.sleep(10);
}
public static class ThreadPrinter implements Runnable{
private String name;//线程名称
private Object prev;//前一个线程
private Object self;//当前线程
private ThreadPrinter(String name,Object prev,Object self){
this.name = name;
this.prev = prev;
this.self = self;
}
public void run() {
int count = 9;
while (count > 0){ //多线程并发,不能用if,必须使用while循环
synchronized (prev){ //先获取prev锁
synchronized (self){ //再获取self锁
System.out.print(name);
count --;
self.notifyAll(); //self锁执行完,唤醒其他线程竞争self锁,,注意此时self锁并未立即释放。
//notifyAll()方法(唤醒所有 wait 线程)
//notify()方法(只随机唤醒一个 wait 线程)
}
// 此时执行完self的同步块,这时self锁才释放。
try{
if(count == 0){ //代表最后一次打印,则唤醒所有prev进程,释放prev对象锁
prev.notifyAll();
} else{
prev.wait(); // 立即释放 prev锁,当前线程休眠,等待唤醒
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
}
三、Lock->ReentrantLock 和 state标志
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 60055558
* @version 1.0
*/
public class ThreadPrinter02 {
private static Lock lock = new ReentrantLock();
private static int state = 0;//通过state的值来确定是哪个线程打印
public static void main(String[] args) {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
//public static class ThreadPrinter implements Runnable{}
public static class ThreadA extends Thread {
public void run(){
for (int i=0;i<10;){
try{
lock.lock();
while (state%3 == 0){// 多线程并发,不能用if,必须用循环测试等待条件,避免虚假唤醒
System.out.print("A");
state ++;
i ++ ;
}
}finally{
lock.unlock();
}
}
}
}
public static class ThreadB extends Thread {
public void run(){
for (int i=0;i<10;){
try{
lock.lock();
while (state%3 == 1){
System.out.print("B");
state ++;
i ++ ;
}
}finally{
lock.unlock();
}
}
}
}
public static class ThreadC extends Thread {
public void run(){
for (int i=0;i<10;){
try{
lock.lock();
while (state%3 == 2){
System.out.print("C");
state ++;
i ++ ;
}
}finally{
lock.unlock();
}
}
}
}
}
四、Lock->ReentrantLock 和Condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 60055558
* @version 1.0
*/
public class ThreadPrinter03 {
private static Lock lock = new ReentrantLock();
private static Condition A = lock.newCondition();//Condition是被绑定到Lock上的,必须使用lock.newCondition()才能创建一个Condition
private static Condition B = lock.newCondition();
private static Condition C = lock.newCondition();
private static int count = 0;
public static void main(String[] args) {
new ThreadPrintA().start();
new ThreadPrintB().start();
new ThreadPrintC().start();
}
public static class ThreadPrintA extends Thread{
public void run(){
try{
lock.lock();
for(int i=0;i<10;i++){
while (count % 3 != 0){//注意这里是不等于0,也就是说没轮到该线程执行,之前一直等待状态
A.await();//该线程A将会释放lock锁,构造成节点加入等待队列并进入等待状态
}
System.out.print("A");
count++;
B.signalAll();// A执行完唤醒B线程
}
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
public static class ThreadPrintB extends Thread{
public void run(){
try{
lock.lock();
for(int i=0;i<10;i++){
while(count % 3 != 1){
B.await();// B释放lock锁,当前面A线程执行后会通过B.signalAll()唤醒该线程
}
System.out.print("B");
count ++;
C.signalAll();// B执行完唤醒C线程
}
}catch (Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
public static class ThreadPrintC extends Thread{
public void run(){
try{
lock.lock();
for(int i=0;i<10;i++){
while(count % 3 != 2){
C.await();// C释放lock锁
}
System.out.print("C");
count ++;
A.signalAll();// C执行完唤醒A线程
}
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
五、AtomicInteger
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author 60055558
* @version 1.0
*/
public class ThreadPrinter04 {
private AtomicInteger ai = new AtomicInteger(0);
private static final int MAX_SYC_VALUE = 9;
public static void main(String[] args) {
ThreadPrinter04 print = new ThreadPrinter04();
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 4, 5, TimeUnit.MILLISECONDS, new SynchronousQueue());
executor.execute(print.new ThreadPrintA());
executor.execute(print.new ThreadPrintB());
executor.execute(print.new ThreadPrintC());
executor.shutdown();
}
private class ThreadPrintA implements Runnable{
public void run() {
while (ai.get() < MAX_SYC_VALUE){
if(ai.get() % 3 == 0){
System.out.print("A");
ai.getAndIncrement();
}
}
}
}
private class ThreadPrintB implements Runnable{
public void run() {
while (ai.get() < MAX_SYC_VALUE){
if(ai.get() % 3 == 1){
System.out.print("B");
ai.getAndIncrement();
}
}
}
}
private class ThreadPrintC implements Runnable{
public void run() {
while (ai.get() < MAX_SYC_VALUE){
if(ai.get() % 3 == 2){
System.out.print("C");
ai.getAndIncrement();
}
}
}
}
}
参考文章
https://blog.csdn.net/hefenglian/article/details/82596072