就在网上随便找了几家招聘的,条件都是15-20K,放在武汉相当于中等偏上了,北上广深的就别看了,
出现的一个频率非常高的词汇,多线程、多线程编程、说说你对多线程的理解等等,其实我出去面试面试官一般都是会让你自己讲一些场景,然后根据场景讲讲遇到的问题,所以这个时候加入问到的场景涉及到多线程,如果知道多线程的一些技术以及场景,没做过,能说出来也是可以的。
所以,根据鄙人7年的编程经验,以及了解相关方面的知识,小弟不才,整理了部分多线程的代码实例以及框架,以及多线程的缺点等等。
多线程的依赖包,基于现在用户还是比较多的JDK8提供的API来写一些实例代码。
世间万物都可以同时完成很多工作。例如,人体可以同时进行呼吸、血液循环、思考问题等活动。用户既可以使用计算机听歌,也可以编写文档和发送邮件,而这些活动的完成可以同时进行。这种同时执行多个操作的“思想”在 [Java]中被称为并发,而将并发完成的每一件事称为线程。 在 Java 中,并发机制非常重要,但并不是所有程序语言都支持线程。在以往的程序中,多以一个任务完成以后再进行下一个任务的模式进行,这样下一个任务的开始必须等待前一个任务的结束。Java 语言提供了并发机制,允许开发人员在程序中执行多个线程,每个线程完成一个功能,并与其他线程并发执行。这种机制被称为多线程。
我们在工作中,各种相关服务、数据库、api的调用,有返回时间的差异,这个时候必须使用多线程了。
异步编程的难点:
Java5之后就引入Future用于异步编程,通过get()方法来对异步执行结果的同步等待和结果获取:
Future<String> doSomething = Executors.newSingleThreadExecutor().submit(() -> { try { Thread.sleep(1000 * 3); } catch (InterruptedException e) { e.printStackTrace(); } return "success"; }); String result = doSomething.get(); System.out.println(result);
Future的Api比较简单,而已对异常处理不友好,如果有同时有多个异步操作需要同时进行是就不好处理了
假设有这么一个场景,用户登录拿到登录凭证(token),登录之后获取用户信息。
ExecutorService executors = Executors.newFixedThreadPool(10); Future<String> login = executors.submit(()->login()); String token = login.get(); Future<String> userInfo = executors.submit(() -> userInfo(token)); String userInfoResult = userInfo.get(); System.out.println(userInfoResult);
这种实现方法还是不能实现真正的异步编程或者说不是我们所期望的,我们期望的是登录后获取用户信息,但这两件事情完成后统一对结果进行处理,而这种方式是先等待登录之后再取用户信息,和同步调用类似,这就与我们的设想不符。
初识CompletableFuture
在Java8中引入了CompletableFuture类,同时实现了Future接口和CompletionStage接口,提供了一套用于异步编程的Api接口并且提供了异步处理
CompletableFuture提供了许多异步编程的操作,可以说是Java中.的Promise了,下面通过CompletableFuture来实现上面提到的例子:
String userInfo = CompletableFuture.supplyAsync(() -> login()) .thenApplyAsync(token -> userInfo(token)) .get(); System.out.println(userInfo);
CompletableFuture API
CompletableFuture方法很多,功能也很丰富,这里不一一说明,主要可以分为这几类来使用:
CompletableFuture实现了Future接口,也就是Future能做的CompletableFuture也同样能使用,加上complete和completeExceptionally方法可以控制结果的结束
CompletableFuture<String> f = new CompletableFuture<>(); Executors.newSingleThreadExecutor().submit(()->{ f.complete("hello"); //f.completeExceptionally(new RuntimeException("error")); }); String result = f.get(); System.out.println(result);
可以通过CompletableFuture来控制多个异步操作同时执行:
CompletableFuture<String> f = new CompletableFuture<>(); new Thread(() -> { try { System.out.println("thread1:" + f.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { System.out.println("thread2:" + f.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }).start(); f.complete("hello");
创建异步操作的方法主要是:
public static CompletableFuture<Void> runAsync(Runnable runnable) public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
使用如下:
CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "hello"; }); String result = f.get(); System.out.println(result);
public CompletableFuture<Void> thenRun(Runnable action) public CompletableFuture<Void> thenRunAsync(Runnable action) public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor) public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) public CompletableFuture<Void> thenAccept(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)
使用如下:
CompletableFuture<Void> f = CompletableFuture .supplyAsync(() -> "hello") .thenApplyAsync(res -> res + " world!") .thenAcceptAsync(System.out::println); // wait for job done f.get();
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
使用如下:
CompletableFuture<String> f = CompletableFuture .supplyAsync(() -> "hello") .thenApplyAsync(res -> res + " world!") .whenComplete((res, err) -> { if (err != null) { err.printStackTrace(); } else { System.out.println(res); } }); // wait for job done f.get();
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,Executor executor) public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor)
使用如下:
CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> "Hello") .thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " World,")) .thenCombine(CompletableFuture.supplyAsync(() -> "CompletableFuture!"), (a, b) -> a + b); String result = f.get(); System.out.println(result);//Hello World,CompletableFuture!
// 异常处理 CompletableFuture<Object> f = CompletableFuture.supplyAsync(() -> "Hello") .thenApplyAsync(res -> res + "World") .thenApplyAsync(res -> { throw new RuntimeException("error"); }) .exceptionally(e -> { //handle exception here e.printStackTrace(); return null; }); f.get(); // 执行结果处理 CompletableFuture<Object> f2 = CompletableFuture.supplyAsync(() -> "Hello") .thenApplyAsync(res -> res + "World") .thenApplyAsync(res -> { throw new RuntimeException("error"); }) .handleAsync((res, err) -> { if (err != null) { //handle exception here return null; } else { return res; } }); Object result = f2.get(); System.out.println(result);
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
使用如下:
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "hello"); CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "world"); CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "!"); // 使用allOf方法 CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3); all.get(); System.out.println(f1.get()); System.out.println(f2.get()); System.out.println(f3.get()); // 结合StreamAPI List<String> result = Stream.of(f1, f2, f3) .map(CompletableFuture::join) .collect(Collectors.toList()); System.out.println(result);
Disruptor 是一个 Java 的并发编程框架,大大的简化了并发程序开发的难度,在性能上也比 Java 本身提供的一些并发包要好。
https://www.jianshu.com/p/bad7b4b44e48
netty4可以说是我这些年做数据采集,TCP、UDP、MQTT等用的最多,api最丰富,性能最好而且轻量级的框架。
https://www.cnblogs.com/hunrry/p/9408394.html
Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型, [1] 让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言 。
近年来,移动网络、社交网络和电商的兴起,使各大服务提供商的客户端请求数量激增,传统服务器架构已不堪重负,致使基于事件和异步的解决方案备受追捧,如Nginx、NodeJS。Vert.x框架基于事件和异步,依托于全异步Java服务器Netty,并扩展了很多其他特性,以其轻量、高性能、支持多语言开发而备受开发者青睐。
优点:
缺点:
写一句我的感受:
一般情况下我们使用到的多线程,是在该业务场景下,没得办法的选择,所以给我的感觉,多线程是一个进程在多种任务在协同工作时的解决方案,至于解决方案的具体内容那就依靠程序员的经验了,幸好现在最新版的都JDK提供的便捷易懂的API,使得编写难度降低而可读性提高了了。