记录笔试时碰到的一个多线程题目…
做题时的感觉:
1.很多线程方法都忘了,而且对某些关键字的理解会有些刻板印象
2.现在的想法是…看看能不能通过这道题,练习利用idea来进行多线程debug
3.归纳易混淆的和线程生命周期有关的方法(记得当时记在了微信的对话框上)
4.新的内容:阻塞队列及应用,CountDownLatch是基于阻塞队列的应用
当前进度:看了一些多线程打印题,但是不能复写
package com.exampledb.demo.po;
import lombok.SneakyThrows;
public class ThreadTest {
@SneakyThrows
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
Thread t1 = new Thread(() -> {
synchronized (stringBuilder) {
stringBuilder.append("A");
try {
stringBuilder.wait();
} catch (InterruptedException e) {
System.out.println("hhhhhhhh");
}
stringBuilder.append("B");
}
});
Thread t2 = new Thread(() -> {
synchronized (stringBuilder) {
stringBuilder.append("C");
stringBuilder.notify();
stringBuilder.append("D");
}
});
t1.start();
Thread.sleep(300);
t2.start();
t1.join();
t2.join();
System.out.println(stringBuilder.toString());
}
}
ACDB
Java 并发编程:线程间的协作(waittifyeep/yield/join)
Java线程之sleep(), wait(), yield() 三个方法的作用和特点
wait方法的使用必须在同步的范围内,否则就会抛出IllegalMonitorStateException异常,wait方法的作用就是阻塞当前线程等待notify/notifyAll方法的唤醒,或等待超时后自动唤醒
关键:是否会让出锁,是否会让出CPU资源。。还有sync是否能保持原子性,在于线程有没有调用方法把锁放掉,如果没放掉锁,那么就可以保持代码块的原子性
CAS(Compare-and-Swap,即比较并替换)算法
适用场景不同:
CAS与synchronized的对比
简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),
synchronized适用于写比较多的情况下(多写场景,冲突一般较多)
阻塞队列:
多线程环境下控制数据的生产和消费端的数据处理效率匹配。。
比如,生产者有多个线程生产数据,这些线程都放在阻塞队列A里;
消费者有多个线程消费数据,这些线程都放在阻塞队列B里;
当A生产数据太多,B消费不过来时,A里面的线程将会被阻塞,被挂起
阻塞队列demo
代码copy自原文
生产者线程
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 生产者线程
*
* @author jackyuj
*/
public class Producer implements Runnable {
private volatile boolean isRunning = true;//是否在运行标志
private BlockingQueue queue;//阻塞队列
private static AtomicInteger count = new AtomicInteger();//自动更新的值
private static final int DEFAULT_RANGE_FOR_SLEEP = 1000;
//构造函数
public Producer(BlockingQueue queue) {
this.queue = queue;
}
public void run() {
String data = null;
Random r = new Random();
System.out.println("启动生产者线程!");
try {
while (isRunning) {
System.out.println("正在生产数据...");
Thread.sleep(r.nextInt(DEFAULT_RANGE_FOR_SLEEP));//取0~DEFAULT_RANGE_FOR_SLEEP值的一个随机数
data = "data:" + count.incrementAndGet();//以原子方式将count当前值加1
System.out.println("将数据:" + data + "放入队列...");
if (!queue.offer(data, 2, TimeUnit.SECONDS)) {//设定的等待时间为2s,如果超过2s还没加进去返回true
System.out.println("放入数据失败:" + data);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
System.out.println("退出生产者线程!");
}
}
public void stop() {
isRunning = false;
}
}
消费者
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* 消费者线程
*
* @author jackyuj
*/
public class Consumer implements Runnable {
private BlockingQueue<String> queue;
private static final int DEFAULT_RANGE_FOR_SLEEP = 1000;
//构造函数
public Consumer(BlockingQueue<String> queue) {
this.queue = queue;
}
public void run() {
System.out.println("启动消费者线程!");
Random r = new Random();
boolean isRunning = true;
try {
while (isRunning) {
System.out.println("正从队列获取数据...");
String data = queue.poll(2, TimeUnit.SECONDS);//有数据时直接从队列的队首取走,无数据时阻塞,在2s内有数据,取走,超过2s还没数据,返回失败
if (null != data) {
System.out.println("拿到数据:" + data);
System.out.println("正在消费数据:" + data);
Thread.sleep(r.nextInt(DEFAULT_RANGE_FOR_SLEEP));
} else {
// 超过2s还没数据,认为所有生产线程都已经退出,自动退出消费线程。
isRunning = false;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
System.out.println("退出消费者线程!");
}
}
}
测试类
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class BlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
// 声明一个容量为10的缓存队列
BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
//new了三个生产者和一个消费者
Producer producer1 = new Producer(queue);
Producer producer2 = new Producer(queue);
Producer producer3 = new Producer(queue);
Consumer consumer = new Consumer(queue);
// 借助Executors
ExecutorService service = Executors.newCachedThreadPool();
// 启动线程
service.execute(producer1);
service.execute(producer2);
service.execute(producer3);
service.execute(consumer);
// 执行10s
Thread.sleep(10 * 1000);
producer1.stop();
producer2.stop();
producer3.stop();
Thread.sleep(2000);
// 退出Executor
service.shutdown();
}
}
新的疑惑