Vetx.x : EventLoop线程不要锁(Synchronized/ReentrantLock)
来源:互联网 发布:ubuntu提取声卡codec 编辑:程序博客网 时间:2024/05/22 07:41
Vetx.x : EventLoop线程不要锁(Synchronized/ReentrantLock)
vert.x 里面有eventloop线程,而且eventloop线程是绝对不能阻塞的,
但是实际使用中,有时候我们对阻塞理解不深刻,所以一些隐藏的阻塞
没有那么好发现。
eventloop 线程和work线程共用相同的锁
下面的代码是一个简单的例子,用户请求localhost:8133/sync的时候
会在work现场锁sb对象,然后在eventloop线程也要获取sb这个对象的锁。
那么,我们发现,这样eventloop就会超时,可以看下日志。
package concurrency.file.vertx;import io.vertx.core.AbstractVerticle;import io.vertx.core.Future;import io.vertx.core.Vertx;import io.vertx.core.VertxOptions;import io.vertx.ext.web.Router;import io.vertx.ext.web.handler.BodyHandler;/** * work 线程中有锁 * * @author kyle */public class SynchronizedTest { public static class Inner extends AbstractVerticle { StringBuilder sb = new StringBuilder(); public void write(String str) { synchronized (sb) { sb.delete(0, sb.length()); sb.append(str); } } @Override public void start(Future<Void> future) throws Exception { Router route = Router.router(vertx); route.route().handler(BodyHandler.create()); route.route("/sync").handler(context1 -> { vertx.executeBlocking(f -> { foo(); }, f -> { }); vertx.setTimer(1, f -> { write(context1.getBodyAsString()); context1.response().end(); }); }); vertx.createHttpServer() .requestHandler(route::accept) .listen(8133, ar -> { if (ar.failed()) future.fail(ar.cause()); else future.complete(); }); } private void foo() { synchronized (sb) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { VertxOptions vertxOptions = new VertxOptions(); vertxOptions.setMaxEventLoopExecuteTime(20_000_000); Vertx vertx = Vertx.vertx(vertxOptions); vertx.deployVerticle(new Inner(), ar -> { for (int i = 0; i < 50; i++) { vertx.createHttpClient() .getNow(8133, "localhost", "/sync", result -> { System.out.println("finish"); }); } }); }}
日志如下
这是由于两个线程同时抢夺一个锁,如果eventloop线程拿不到锁,它就会阻塞。
仅eventloop中有锁
下面是上面的代码的修改,去掉了work线程对锁的把持。但是这样写代码依然有问题,如果多个eventloop线程
抢夺一个锁,必定会造成其他的eventloop线程的阻塞。所以也不要使用这种写法
package concurrency.file.vertx;import io.vertx.core.AbstractVerticle;import io.vertx.core.Future;import io.vertx.core.Vertx;import io.vertx.core.VertxOptions;import io.vertx.ext.web.Router;import io.vertx.ext.web.handler.BodyHandler;/** * work 线程中有锁 * * @author kyle */public class SynchronizedTest { public static class Inner extends AbstractVerticle { StringBuilder sb = new StringBuilder(); public void write(String str) { synchronized (sb) { sb.delete(0, sb.length()); sb.append(str); } } @Override public void start(Future<Void> future) throws Exception { Router route = Router.router(vertx); route.route().handler(BodyHandler.create()); route.route("/sync").handler(context1 -> { write(context1.getBodyAsString()); context1.response().end(); }); vertx.createHttpServer() .requestHandler(route::accept) .listen(8133, ar -> { if (ar.failed()) future.fail(ar.cause()); else future.complete(); }); } } public static void main(String[] args) { VertxOptions vertxOptions = new VertxOptions(); vertxOptions.setMaxEventLoopExecuteTime(20_000_000); Vertx vertx = Vertx.vertx(vertxOptions); vertx.deployVerticle(new Inner(), ar -> { for (int i = 0; i < 50; i++) { vertx.createHttpClient() .getNow(8133, "localhost", "/sync", result -> { System.out.println("finish"); }); } }); }}
由于这种现象需要高并发的情况下,才容易观察出问题,所以这种写法,经常会被我们忽略。
看不到的synchronize
看下面的一段代码,是不是觉得没有用到锁,不会阻塞线 。其实不是的,由于Files.write底层仍然使用了synchronized 锁,
所以也会阻塞 eventloop线程,这种情况下,我们很难发现和察觉。
package concurrency.file.vertx;import io.vertx.core.AbstractVerticle;import io.vertx.core.Future;import io.vertx.core.Vertx;import io.vertx.core.VertxOptions;import io.vertx.ext.web.Router;import io.vertx.ext.web.handler.BodyHandler;/** * work 线程中有锁 * * @author kyle */public class SynchronizedTest { public static class Inner extends AbstractVerticle { public void write(String str) { Files.write(Path.get("temp"), str.getBytes()); } @Override public void start(Future<Void> future) throws Exception { Router route = Router.router(vertx); route.route().handler(BodyHandler.create()); route.route("/sync").handler(context1 -> { write(context1.getBodyAsString()); context1.response().end(); }); vertx.createHttpServer() .requestHandler(route::accept) .listen(8133, ar -> { if (ar.failed()) future.fail(ar.cause()); else future.complete(); }); } } public static void main(String[] args) { VertxOptions vertxOptions = new VertxOptions(); vertxOptions.setMaxEventLoopExecuteTime(20_000_000); Vertx vertx = Vertx.vertx(vertxOptions); vertx.deployVerticle(new Inner(), ar -> { for (int i = 0; i < 50; i++) { vertx.createHttpClient() .getNow(8133, "localhost", "/sync", result -> { System.out.println("finish"); }); } }); }}
不用锁,我该怎么办
我个人觉得,在Eventloop线程中是绝对不能用锁的,各种锁都不行,比如synchronize ,reentrantLock, CountdownLatch, CycleBarrier等等。那我们如何处理同步问题呢。我的一个思路是用单线程池,不用加锁,天然保持线程的同步。参考列子,如下。
package concurrency.file.vertx; import io.vertx.core.AbstractVerticle; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * work 线程中有锁 * * @author kyle */ public class SynchronizedTest { public static class Inner extends AbstractVerticle { ExecutorService executorService = Executors.newSingleThreadExecutor(); StringBuilder sb = new StringBuilder(); public Future<Void> write(String str) { Future<Void> future = Future.future(); executorService.submit(() -> { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } sb.delete(0, sb.length()); sb.append(str); }); return future; } @Override public void start(Future<Void> future) throws Exception { Router route = Router.router(vertx); route.route().handler(BodyHandler.create()); route.route("/sync").handler(context1 -> { write(context1.getBodyAsString()); context1.response().end(); }); vertx.createHttpServer() .requestHandler(route::accept) .listen(8133, ar -> { if (ar.failed()) future.fail(ar.cause()); else future.complete(); }); } } public static void main(String[] args) { VertxOptions vertxOptions = new VertxOptions(); vertxOptions.setMaxEventLoopExecuteTime(20_000_000); Vertx vertx = Vertx.vertx(vertxOptions); vertx.deployVerticle(new Inner(), ar -> { for (int i = 0; i < 50; i++) { vertx.createHttpClient() .getNow(8133, "localhost", "/sync", result -> { System.out.println("finish"); }); } }); } }
阅读全文
0 0
- Vetx.x : EventLoop线程不要锁(Synchronized/ReentrantLock)
- synchronized ReentrantLock 线程安全
- 线程同步方法、性能比较(synchronized,ReentrantLock,Atomic)
- ReentrantLock(一):谈谈ReentrantLock与synchronized
- ReentrantLock与synchronized同步锁
- synchronized和锁(ReentrantLock) 区别
- ReentrantLock与synchronized (顶)
- java锁机制(四)-----------ReentrantLock与synchronized对比
- Java 中的锁(1)synchronized与ReentrantLock
- Java 多线程(四)——线程同步(synchronized、ReentrantLock)
- Java 多线程(四)——线程同步(synchronized、ReentrantLock)
- ReentrantLock 线程锁
- ReentrantLock锁与内置锁synchronized
- ReentrantLock锁与内置锁synchronized
- Synchronized和ReentrantLock包装线程不安全的类_demo
- java线程同步:synchronized关键字,Lock接口以及可重入锁ReentrantLock
- 【Java基础之线程同步(二)】java线程同步:synchronized关键字,Lock接口以及可重入锁ReentrantLock
- synchronized与ReentrantLock锁机制对比
- 链表
- devexpress 上下滚动条
- 如何定位Android NDK开发中遇到的错误
- Android的项目应用总结
- 页面加载完不在顶部
- Vetx.x : EventLoop线程不要锁(Synchronized/ReentrantLock)
- java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.
- 一般对数组初始化可以用以下方法实现
- 学生管理系统(五)---修改窗体
- 操作系统
- 3 3 8 8四则运算得24
- iDomain
- CSS定位
- RxJava2.0 使用心得(1)