面试题
要求用线程顺序打印A1B2C3…Z26
LockSupport
package character07;
import java.util.concurrent.locks.LockSupport;
/**
* @author laimouren
*/
public class T08_00_LockSupport {
static Thread t1 = null,t2=null;
public static void main(String[] args) throws Exception{
char[] char1_7 = "1234567".toCharArray();
char[] charA_G = "ABCDEFG".toCharArray();
t1 = new Thread(()->{
for (char c :char1_7){
System.out.println(c);
LockSupport.unpark(t2); //叫醒T2
LockSupport.park();//T1线程阻塞
}
},"t1");
t2 = new Thread(()->{
for (char c :charA_G){
LockSupport.park();//T2线程阻塞
System.out.println(c);
LockSupport.unpark(t1); //叫醒T1
}
},"t2");
t1.start();
t2.start();
}
}
sync + wait + notify
package character07;
/**
* @Author laimouren
* @Date 2022/1/5 9:15
*/
public class Sync_wait_notify {
public static void main(String[] args) {
final Object o = new Object();
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(()->{
synchronized (o) {
for(char c : aI) {
System.out.print(c);
try {
o.notify(); //叫醒其他线程 不会出让锁
o.wait(); // 线程阻塞 让出锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify(); //必须,否则无法停止程序
}
}, "t1").start();
new Thread(()->{
synchronized (o) {
for(char c : aC) {
System.out.print(c);
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
o.notify();
}
}, "t2").start();
}
}
Condition
package character07;
/*
* Condition本质是锁资源上不同的等待队列
* @Auther laimouren
*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class T09_00_lock_condition {
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
Lock lock = new ReentrantLock();
Condition conditionT1 = lock.newCondition();
Condition conditionT2 = lock.newCondition();
new Thread(()->{
try {
lock.lock();
for(char c : aI) {
System.out.println(c);
conditionT2.signal();//叫醒另一个
conditionT1.await();//当前的等待
}
conditionT2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1").start();
new Thread(()->{
try {
lock.lock();
for(char c : aC) {
System.out.println(c);
conditionT1.signal();
conditionT2.await();
}
conditionT1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t2").start();
}
}
CAS
package character07;
/*
* @Auther laimouren
*/
public class T03_00_cas {
enum ReadyToRun {T1, T2}
static volatile ReadyToRun r = ReadyToRun.T1; //思考为什么必须volatile:保证线程可见性
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(() -> {
for (char c : aI) {
while (r != ReadyToRun.T1) {}
System.out.println(c);
r = ReadyToRun.T2;
}
}, "t1").start();
new Thread(() -> {
for (char c : aC) {
while (r != ReadyToRun.T2) {}
System.out.println(c);
r = ReadyToRun.T1;
}
}, "t2").start();
}
}
BlockingQueue(纯炫技)
package character07;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @Author laimouren
* @Date 2022/1/5 9:38
*/
public class T10_00_BlockingQueue {
static BlockingQueue<String> q1 = new ArrayBlockingQueue<>(1);
static BlockingQueue<String> q2 = new ArrayBlockingQueue<>(1);
public static void main(String[] args) {
char[] aI = "1234567".toCharArray();
char[] aC = "ABCDEFG".toCharArray();
new Thread(()->{
for (char c: aI) {
System.out.println(c);
try{
//线程1先往q1添加值
q1.put("ok");
//线程1往q2里拿值,q2没有值则会在这阻塞住
q2.take();
}catch (InterruptedException e){
e.printStackTrace();
}
}
},"t1").start();
new Thread(()->{
for (char c: aC) {
try{
//线程2判断线程1是否往q1添加了ok,没有则线程会在这阻塞住
q1.take();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(c);
try {
//线程2往q2里放值,以确保线程1继续执行
q2.put("ok");
}catch (InterruptedException e){
e.printStackTrace();;
}
}
},"t2").start();
}
}
线程池常用类
Executor
执行器,这是一个接口,内部维护了一个方法execute它负责执行一项任务。参数为Runnable,方法的具体实现由我们自己来执行。
定义与运行分开
/**
The Executor implementations provided in this package implement ExecutorService, which is a more extensive interface. The ThreadPoolExecutor class provides an extensible thread pool implementation. The Executors class provides convenient factory methods for these Executors.
Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.
**/
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
如下面的代码,我们既可以使用单纯的方法调用也可以新启一个新的线程去执行Runnable的run方法。
package character07.ThreadPool;
import java.util.concurrent.Executor;
public class T01_MyExecutor implements Executor {
public static void main(String[] args) {
new T01_MyExecutor().execute(()->System.out.println("hello executor"));
}
@Override
public void execute(Runnable command) {
//new Thread(command).run();
command.run();
}
}
ExecutorService
代表着启动一系列的线程为用户提供服务(本质上也是一个执行器),比如说Java8的官方文档就举了一个网络接受连接池的例子(代码如下)。在这里ExecutorService就代表着一个的线程池对外提供接受网络请求的服务。同时它也是一系列线程池的接口比如说
RorkJoinPool、ScheduledThreadPoolExecutor,、ThreadPoolExecutor等。同时它可以提交Callable与Runnable的对象返回一个未来的执行结果对象Future。
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize)
throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void run() { // run the service
try {
for (;;) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request on socket
}
}
除了以上方法来创建一个ExecutorService还可以使用Executors这个工具类来创建它,在这里我们可以把Executors理解为就像utils,collections的工具类。
Callable
Callable是一个增强版的Runnable,它的call方法可以抛出异常可以有返回值。其中它的返回值放在了Future对象中,我们可以使用Future对象的get方法来获得返回值。
package character07.ThreadPool;
import java.util.concurrent.*;
/**
* @Author laimouren
* @Date 2022/1/5 10:25
*/
public class T03_Callable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> c = new Callable<String>() {
@Override
public String call() throws Exception {
return "Hello callable";
}
};
ExecutorService service = Executors.newCachedThreadPool();
Future<String> future = service.submit(c);//异步执行
//get方法是阻塞的
System.out.println(future.get());
service.shutdown();
}
}
Future
== 将来的结果==
Future常与Callable联合使用,Future可以获得Callable执行后的返回值。如果想新建一个线程执行一个这个Callable中的call方法而且获得返回值的话我们可以使用以下的思路。
方案一:new Thread(new FutureTask().start();使用FutureTask来接收任务的返回值。
方案二:new一个线程池然后然后提交Callable的实现的对象。使用Future来获得Callable的返回值。
FutureTask
实现了RunnableFuture接口,而RunnableFuture又实现了Runable接口和Future接口,所以即可以运行,也可以储存返回值
package character07.ThreadPool;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
public class T06_Future {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> task = new FutureTask<>(()->{
TimeUnit.MILLISECONDS.sleep(500);
return 1000;
}); //new Callable () { Integer call();}
new Thread(task).start();
System.out.println(task.get()); //阻塞
//*******************************
ExecutorService service = Executors.newFixedThreadPool(5);
Future<Integer> f = service.submit(()->{
TimeUnit.MILLISECONDS.sleep(500);
return 1;
});
System.out.println(f.get());
System.out.println(f.isDone());
}
}
Callable、Future和FutureTask
Callable->Runnable + ret
Future -> 存储执行的将来才会产生的结果
FutureTask->Future + Runnable
CompletableFuture
线程池
- ThreadPoolExecutor
- ForkJoinPool
ThreadPoolExecutor
继承自AbstractExecutorService,而AbstractExecutorService又实现了ExecutorService接口
深入理解ThreadPoolExecutor
线程池定义
维护着两个集合,一个是线程集合,一个是任务集合
线程池7个参数
第一个参数corePoolSize 核心线程数
第二个参数maxmumPoolSize 最大线程数
第三个参数keepAliveTime 空闲时间 如果到了指定空闲时间线程都没有干活 将归还给操作系统
第四个参数是第三个参数的单位
第五个参数 BlockingQueue 阻塞队列
第六个参数 默认的线程工厂,自己可以定义线程工厂生产想要的线程
第七个参数 拒绝策略 线程忙,而且任务队列满的时候,要执行的拒绝策略
拒绝策略:
- Abort 抛异常
- Discard 扔掉,不抛异常
- DiscardOldest 扔掉排队时间最久的
- CallerRuns 调用者处理任务
- 一般情况下都是自定义
定义线程池
package character07.ThreadPool;
/*
* @Auther laimouren
*/
import java.io.IOException;
import java.util.concurrent.*;
public class T05_00_HelloThreadPool {
static class Task implements Runnable {
private int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Task " + i);
try {
//阻塞
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "Task{" +
"i=" + i +
'}';
}
}
public static void main(String[] args) {
//ThreadPool 维护着两个内容 一个是线程队列 另外一个是任务队列
//线程池7个参数
//corePoolSize 核心线程数
//maxmumPoolSize 最大线程数
//keepAliveTime 空闲时间 如果空闲时间线程没有干活 将归还给操作系统
//第五个参数 BlockingQueue 阻塞队列 看源码 ThreadPoolExecutor()构造方法 BlockingQueue<Runnable> workQueue
//第六个参数 默认的线程工厂
//第七个参数 拒绝策略 线程忙 而且任务队列满的时候 要执行的拒绝策略
//拒绝策略有 Abort 抛异常 Discard 扔掉 DiscardOldest 扔掉排队时间最久的 CallerRuns 调用者处理任务
ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4,
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(4),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 8; i++) {
tpe.execute(new Task(i));
}
System.out.println(tpe.getQueue());
tpe.execute(new Task(100));
System.out.println(tpe.getQueue());
tpe.shutdown();
}
}
ForkJoinPool
分解汇总的任务
用很少的线程可以执行很多的任务(子任务)ThreadPoolExecutor做不到先执行子任务
CPU密集型