Java依次打印abcdefg_多个线程分别顺序交替打印一种不同字符abcdefg(已实现随便多少个线程打印多少个字符,利用线程池实现多线程)...

下面实现多线程顺序打印字符"abcdefg";

实现Runnable接口:

/***@author: rhyme

* @date: 2019-08-17 14:39

* @topic: "Runnable"

* @description: "每个线程通过sign表示需要打印的字符数组下标,index表示将要打印的字符数组的下标"*/

public class PrintRunnable implementsRunnable {private final char[] chars;/*** 当前线程只能打印的那个字符对应数组的下标*/

private final intsign;/*** 当前将要打印的字符数组下标*/

private volatile static intindex;private final static Class CLASS_LOCK = PrintRunnable.class;public PrintRunnable(String chars, intsign) {this.chars =chars.toCharArray();this.sign =sign;

}

@Overridepublic voidrun() {try{while (true) {//为了结合线程池shutdownNow方法设置中断interrupt停止线程

/*if (Thread.currentThread().isInterrupted()) {

break;

}*/

synchronized(CLASS_LOCK) {if (index % chars.length ==sign) {

System.out.printf("ThreadName : %s is printing (%c)\n", Thread.currentThread().getName(), chars[sign]);

index++;

CLASS_LOCK.notifyAll();

}

CLASS_LOCK.wait();

}

}

}catch(InterruptedException e) {

e.printStackTrace();

System.err.printf("ThreadName : %s InterruptedException\n", Thread.currentThread().getName());

}

}

}

这里实现Runnable接口,两个重要的属性sign和index;

sign表示当前线程打印的那个字符在字符数组中的下标;

index表示移动字符下标打印, index % chars.length(重要,顺序打印的核心实现)的值表示需要打印的字符的下标,当一个字符被打印,index++;

chars表示一个字符数组;

wait()这里有两个作用,一个是为了让当前线程等待不马上循环获取锁影响效率,另一个可以通过设置线程中断interrupt抛异常停止;

notifyAll唤醒所有对应锁wait()的线程;

这里也可以不用wait和notifyAll,那每个线程就不会wait,重复循环获取锁,占用资源影响效率,其次可判断线程是否被设为中断,则break退出循环。

利用线程池启动:

importcom.google.common.util.concurrent.ThreadFactoryBuilder;import java.util.concurrent.*;/***@author: rhyme

* @date: 2019-08-17 14:37

* @topic: "多个线程打印"

* @description: "多个线程有序打印abcdefg"*/

public classMultiThreadPrintOrder {public static void main(String[] args) throwsInterruptedException {

final String string= "abcdefg";

ThreadFactory namedThreadFactory= newThreadFactoryBuilder()

.setNameFormat("order-pool-%d")

.build();

ExecutorService threadPoolExecutor=

newThreadPoolExecutor(

string.length(),

string.length(),0L,

TimeUnit.SECONDS,new ArrayBlockingQueue<>(1),

namedThreadFactory,newThreadPoolExecutor.AbortPolicy());for (int i = 0; i < string.length(); i++) {

threadPoolExecutor.execute(newPrintRunnable(string, i));

}//3秒后线程池调用shutdownNow设置线程中的interrupt中断标志位

TimeUnit.SECONDS.sleep(3);

System.out.printf("ThreadName: (%s) Preparing call shutdownNow()...\n", Thread.currentThread().getName());

threadPoolExecutor.shutdownNow();

}

}

这里通过guava包中ThreadFactoryBuilder设置线程池中的线程名;

提交string.length()个不同的线程任务(通过下标i打印不同的字符)到线程池中;

3秒后,主线程调用shutdownNow,这里主要是为了将正在运行的线程设置中断标志位,死循环利用中断标志位结束循环,或线程调用了等待方法(如wait)会抛出异常InterruptException未被捕获而停止。

shutdownNow 方法:此方法执行后不得向线程池再提交任务,如果有空闲线程则销毁空闲线程,取消所有位于阻塞队列中的任务,并将其放入 List容器,作为返回值;取消正在执行的线程(实际上仅仅是设置正在执行线程的中断标志位,调用线程的 interrupt 方法来中断线程)。

启动main方法,多个线程按顺序打印"abcdefg",3s后结束,执行结果部分截图如下:

56f63ebe1d631fd55f0528d83c6aa2e6.png

当然也可以通过另一种"等待-唤醒"机制实现,如用一个ReentrantLock对象的的newCondition()方法创建多个Condition对象,再利用Condition对象的await()搭配signal()或signalAll();

也可利用取余运算%判断线程需要打印的字符,不用生成多个 Condition对象,可利用一个Condition对象,而且可以改变,随便多少个线程打印多少个字符。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值