用三个线程按顺序循环打印abc 三个字母,比如abcabcabc

线程类:


import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Andrew  on 2017/3/22.
 * update on 2019/12/08 unlock规范化,默认不限制打印次数
 */
public class PrintThread implements Runnable{
    private String symbol;
    private Condition conditionA =null;
    private int go = 0;
    private ReentrantLock lock =null;
    //使用原子类,本例中并没有多大意义
    private static AtomicInteger i=new AtomicInteger(0);

    public PrintThread(String symbol, Condition conditionA,int go,ReentrantLock lock) {
        this.symbol = symbol;
        this.lock = lock;
        this.conditionA = conditionA;
        this.go = go;
    }
    @Override
    public void run() {
        while (true){
            lock.lock();
            try {
                try {
                    while (i.get() % 3 != go) {
                        conditionA.await();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //防止过多输出
//            if (i.get()==10)break;
                System.out.println("result " + symbol);
                i.getAndIncrement();
//            System.out.println(i.get());
                //可以试试signalAll或signal区别,比较时建议去掉前面的break
                conditionA.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }
}


main函数:


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Andrew  on 2017/3/22.
 */
public class PrintLetter {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition conditionA = lock.newCondition();
    public static void main(String[] args) throws InterruptedException {
        new Thread(new PrintThread("A",conditionA,0,lock)).start();
        new Thread(new PrintThread("B",conditionA,1,lock)).start();
        new Thread(new PrintThread("C",conditionA,2,lock)).start();
    }

}

下面这种实现是我最初的想法但当时并没能实现,这种方式我认为比较巧妙但存在两大问题:

1.达到目的后仍有线程处于等待状态。

2.由于运行环境可能达不到最终结果。主要原因是线程调度顺序

 


/**
 * Created by Andrew  on 2017/3/26.
 */
public class MyThreadPrinter implements Runnable {
    private String name;
    private Object prev;
    private Object self;

    private MyThreadPrinter(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }

    @Override
    public void run() {
        int count = 10;
        while (count > 0) {
            synchronized (prev) {
                synchronized (self) {
                    System.out.print(name);
                    count--;

                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) throws Exception {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        MyThreadPrinter pa = new MyThreadPrinter("A", c, a);
        MyThreadPrinter pb = new MyThreadPrinter("B", a, b);
        MyThreadPrinter pc = new MyThreadPrinter("C", b, c);


        new Thread(pa).start();
        new Thread(pb).start();
        new Thread(pc).start();    }
}

错误调度顺序:如果主线程在启动A后,执行A,过程中又切回主线程,启动了ThreadB,ThreadC,之后,由于A线程尚未释放self.notify,也就是B需要在synchronized(prev)处等待,而这时C却调用synchronized(prev)获取了对b的对象锁。这样,在A调用完后,同时ThreadB获取了prev也就是a的对象锁,ThreadC的执行条件就已经满足了,会打印C,之后释放c,及b的对象锁,这时ThreadB具备了运行条件,会打印B,也就是循环变成了ACBACB了

 

最近刚好又接触到了更新一下==========2019/12/08

第一种思路的另一种实现,也可以不加锁依赖原子类同步能力忙等:

public class PrintThread  implements Runnable{
    private String symbol;
    private int go;
    private final Object lock;
    //使用原子类,本例中并没有多大意义
    private static AtomicInteger i = new AtomicInteger(0);

    public PrintThread(String symbol, int go, Object lock) {
        this.symbol = symbol;
        this.lock = lock;
        this.go = go;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                try {
                    while (i.get() % 3 != go) {
                        lock.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //防止过多输出
//            if (i.get()==10)break;
                System.out.println(Thread.currentThread().getName() + " "+ symbol);
                i.getAndIncrement();
//            System.out.println(i.get());
                //可以试试signalAll或signal区别,比较时建议去掉前面的break
                lock.notifyAll();
            }
        }
    }
}

使用阻塞队列实现:

public class PrintThread implements Runnable {
    private String symbol;
    private BlockingQueue<String> messageQueue;
    private BlockingQueue<String> putQueue;

    public PrintThread(String symbol, BlockingQueue<String> messageQueue, BlockingQueue<String> putQueue) {
        this.symbol = symbol;
        this.messageQueue = messageQueue;
        this.putQueue = putQueue;
    }

    @Override
    public void run() {
        while (true) {
            String message = null;
            try {
                message = messageQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " "+ message);
            putQueue.add(symbol);
        }
    }
}

初始化方法,还可以通过初始化参数调整打印结果:

    public static void main(String[] args) {
        BlockingQueue<String> messageQueueA = new ArrayBlockingQueue<>(1);
        BlockingQueue<String> messageQueueB = new ArrayBlockingQueue<>(1);
        BlockingQueue<String> messageQueueC = new ArrayBlockingQueue<>(1);

        messageQueueA.add("A");
        new Thread(new PrintThread("B", messageQueueA, messageQueueB)).start();
        new Thread(new PrintThread("C", messageQueueB, messageQueueC)).start();
        new Thread(new PrintThread("A", messageQueueC, messageQueueA)).start();
    }

单个阻塞队列实现,线程忙等浪费CPU资源:

public class PrintThread implements Runnable {
    private String symbol;
    private String putSymbol;
    private BlockingQueue<String> queue;

    public PrintThread(String symbol, String putSymbol, BlockingQueue<String> queue) {
        this.symbol = symbol;
        this.putSymbol = putSymbol;
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            while (!symbol.equals(queue.peek()));
            queue.remove();
            System.out.println(Thread.currentThread().getName() + " "+ symbol);
            queue.add(putSymbol);
        }
    }
}

初始化方法:

    public static void main(String[] args) {
        BlockingQueue<String> messageQueue = new ArrayBlockingQueue<>(1);
        messageQueue.add("A");
        new Thread(new PrintThread("A", "B", messageQueue)).start();
        new Thread(new PrintThread("B", "C", messageQueue)).start();
        new Thread(new PrintThread("C", "A", messageQueue)).start();
    }

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
为了实现三个线程循环打印ABC,可以使用Synchronized同步方法和Object的wait()和notify()方法。首先,创建三个线程A、B、C,并设置它们的打印次数为10。然后,通过使用三个对象锁a、b、c来控制线程的执行顺序。A线程首先获得c对象锁,打印A后释放c对象锁,并通过notify()方法唤醒B线程。B线程等待a对象锁,获取到a对象锁后打印B,并释放a对象锁,然后通过notify()方法唤醒C线程。C线程等待b对象锁,获取到b对象锁后打印C,并释放b对象锁,并通过notify()方法唤醒A线程。这样就实现了三个线程循环打印ABC的需求。 以下是一个示例代码: ```java class PrintThread implements Runnable { private static final Object a = new Object(); private static final Object b = new Object(); private static final Object c = new Object(); private String name; public PrintThread(String name) { this.name = name; } @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (name) { try { switch (name) { case "A": synchronized (c) { System.out.print("A"); c.notify(); } name.wait(); break; case "B": synchronized (a) { System.out.print("B"); a.notify(); } name.wait(); break; case "C": synchronized (b) { System.out.print("C"); b.notify(); } name.wait(); break; } } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class Main { public static void main(String[] args) { Thread threadA = new Thread(new PrintThread("A")); Thread threadB = new Thread(new PrintThread("B")); Thread threadC = new Thread(new PrintThread("C")); threadA.start(); threadB.start(); threadC.start(); } } ``` 通过以上代码,三个线程将按照ABCABCABC顺序循环打印10次。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [多线程交替打印ABC的多种实现方法](https://blog.csdn.net/xiaokang123456kao/article/details/77331878)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [三个线程轮流打印ABC](https://blog.csdn.net/yu1336199790/article/details/118725454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值