我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。
扫描二维码或搜索hairyang001加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。
协程是比线程更轻量级的程序处理单元,也可以说是运行在线程上的线程,由自己控制
1.适用于被阻塞的,且需要大量并发的场景。
2.不适用于,大量计算的多线程,遇到此种情况,更好实用线程去解决。
虽然Java的线程的API封装的很好,使用起来非常的方便,但是使用起来也得小心。首先线程需要耗费资源,所以单个的机器上创建上万个线程很困难,其次线程之间的切换也需要耗费CPU,在线程非常多的情况下导致很多CPU资源耗费在线程切换上,通过提高线程数来提高系统的性能有时候适得其反。你可以看到现在一些优秀的框架如Netty都不会创建很多的线程,默认2倍的CPU core的线程数就已经应付的很好了,比如node.js可以使用单一的进程/线程应付高并发。
纤程使用的资源更少,它主要保存栈信息,所以一个系统中可以创建上万的纤程Fiber,而实际的纤程调度器只需要几个Java线程即可。
我们看一个性能的比较,直观的感受一下Quasar带来的吞吐率的提高。
下面这个例子中方法m1
调用m2
,m2
调用m3
,但是m2
会暂停1秒钟,用来模拟实际产品中的阻塞,m3
执行了一个简单的计算。
通过线程和纤程两种方式我们看看系统的吞吐率(throughput)和延迟(latency)。
package com.zhou.quasar.quasar; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.LongAdder; import java.util.stream.Collectors; import java.util.stream.Stream; import co.paralleluniverse.fibers.Fiber; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.fibers.Suspendable; import co.paralleluniverse.strands.Strand; import co.paralleluniverse.strands.SuspendableRunnable; public class Helloworld { @Suspendable static void m1() throws InterruptedException, SuspendExecution { String m = "m1"; // System.out.println("m1 begin"); m = m2(); // System.out.println("m1 end"); // System.out.println(m); } static String m2() throws SuspendExecution, InterruptedException { String m = m3(); Strand.sleep(1000); return m; } @Suspendable static String m3() { List l = Stream.of(1, 2, 3).filter(i -> i % 2 == 0).collect(Collectors.toList()); return l.toString(); } public static void main(String[] args) throws ExecutionException, InterruptedException { int count = 10000; testFiber(count); testThreadpool(count); } static void testThreadpool(int count) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(count); ExecutorService es = Executors.newFixedThreadPool(200); LongAdder latency = new LongAdder(); LongAdder counter = new LongAdder(); long t = System.currentTimeMillis(); WrappyInteger sum=new WrappyInteger(0); for (int i = 0; i < count; i++) { es.submit(() -> { // Long long1=sum; long start = System.currentTimeMillis(); try { m1(); } catch (InterruptedException e) { e.printStackTrace(); } catch (SuspendExecution suspendExecution) { suspendExecution.printStackTrace(); } start = System.currentTimeMillis() - start; latency.add(start); counter.add(1); sum.i++; latch.countDown(); }); } latch.await(); t = System.currentTimeMillis() - t; long l = latency.longValue() / count; System.out.println("thread pool took: " + t + ", latency: " + l + " ms------"+counter.longValue()+"sum ---"+sum.i); es.shutdownNow(); } static void testFiber(int count) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(count); LongAdder latency = new LongAdder(); LongAdder counter = new LongAdder(); WrappyInteger sum=new WrappyInteger(0); long t = System.currentTimeMillis(); for (int i = 0; i < count; i++) { new Fiber<Void>("Caller", new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { long start = System.currentTimeMillis(); m1(); start = System.currentTimeMillis() - start; counter.add(1); latency.add(start); sum.i++; latch.countDown(); } }).start(); } latch.await(); t = System.currentTimeMillis() - t; long l = latency.longValue() / count; System.out.println("fiber took: " + t + ", latency: " + l + " ms,------"+counter+"--sum"+sum.i); } static class WrappyInteger{ public int i; public WrappyInteger(int i) { this.i = i; } } }
运行这个程序(需要某种instrument, agent--启动时java代理,或者AOT--编译时已完成代理时工作,或者其它,在下面会介绍),输出结果为:
QUASAR WARNING: Quasar Java Agent isn't running. If you're using another instrumentation method you can ignore this message; otherwise, please refer to the Getting Started section in the Quasar documentation. fiber took: 1382, latency: 1015 ms,------10000--sum10000 thread pool took: 50184, latency: 1000 ms------10000sum ---9999
1、Quasar Java Agent
Quasar java agent可以在运行时动态修改字节码,将下面一行加搭配java命令行中即可,注意把path-to-quasar-jar.jar替换成你实际的quasar java的地址。
-javaagent:path-to-quasar-jar.jar
2、AOT(Ahead-of-Time)
另外一种是在编译时的时候完成instrumentation
<plugin> <groupId>com.vlkan</groupId> <artifactId>quasar-maven-plugin</artifactId> <version>0.7.3</version> <configuration> <check>true</check> <debug>true</debug> <verbose>true</verbose> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>instrument</goal> </goals> </execution> </executions> </plugin>
3、在Web容器中
如果你使用web容器使用基于Quasar的库comsat等,比如Tomcat,则比较棘手。因为你不太像将Quasar java agent直接加到tomcat的启动脚本中,这样会instrument所有的应用,导致很多的警告。
Comsat提供了Tomcat和Jetty的解决方案。
Tomcat
对于tomcat,你可以把comsat-tomcat-loader-0.7.0-jdk8.jar
或者comsat-tomcat-loader-0.7.0.jar
加入到tomcat的common/lib
或者lib
中,然后在你的web应用META-INF/context.xml
中加入:
1 |
|
Jetty
如果使用Jetty,则把comsat-jetty-loader-0.7.0-jdk8.jar
或者comsat-jetty-loader-0.7.0.jar
加入到Jetty的lib中,然后在你的context.xml中加入<Set name="classLoader">
:
1 2 3 4 5 6 7 8 9 10 11 |
|
总之,通过实现一个定制的ClassLoader实现instrumentation。
官方提供文档地址:http://docs.paralleluniverse.co/quasar/
转载:https://www.cnblogs.com/z-test/p/9435847.html
推荐内容:
Java高级面试题及答案
JAVA中的线程安全与非线程安全
java 面试题
JAVA面试题(8)
BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock
一个两年Java的面试总结
顽石系列:Java技术面试
Java在常见的spring面试问题TOP50
阿里面试回来,想和Java程序员谈一谈
京东面试题 Java相关