-
2019-08-07 11:24:32
什么是线程阻塞?
在某一时刻某一个线程在运行一段代码的时候,这时候另一个线程也需要运行,但是在运行过程中的那个线程执行完成之前,另一个线程是无法获取到CPU执行权的(调用sleep方法是进入到睡眠暂停状态,但是CPU执行权并没有交出去,而调用wait方法则是将CPU执行权交给另一个线程),这个时候就会造成线程阻塞。
为什么会出现线程阻塞?
1.睡眠状态:当一个线程执行代码的时候调用了sleep方法后,线程处于睡眠状态,需要设置一个睡眠时间,此时有其他线程需要执行时就会造成线程阻塞,而且sleep方法被调用之后,线程不会释放锁对象,也就是说锁还在该线程手里,CPU执行权还在自己手里,等睡眠时间一过,该线程就会进入就绪状态,典型的“占着茅坑不拉屎”;
2.等待状态:当一个线程正在运行时,调用了wait方法,此时该线程需要交出CPU执行权,也就是将锁释放出去,交给另一个线程,该线程进入等待状态,但与睡眠状态不一样的是,进入等待状态的线程不需要设置睡眠时间,但是需要执行notify方法或者notifyall方法来对其唤醒,自己是不会主动醒来的,等被唤醒之后,该线程也会进入就绪状态,但是进入就绪状态的该线程手里是没有执行权的,也就是没有锁,而睡眠状态的线程一旦苏醒,进入就绪状态时是自己还拿着锁的。等待状态的线程苏醒后,就是典型的“物是人非,大权旁落“;
3.礼让状态:当一个线程正在运行时,调用了yield方法之后,该线程会将执行权礼让给同等级的线程或者比它高一级的线程优先执行,此时该线程有可能只执行了一部分而此时把执行权礼让给了其他线程,这个时候也会进入阻塞状态,但是该线程会随时可能又被分配到执行权,这就很”中国化的线程“了,比较讲究谦让;
4.自闭状态:当一个线程正在运行时,调用了一个join方法,此时该线程会进入阻塞状态,另一个线程会运行,直到运行结束后,原线程才会进入就绪状态。这个比较像是”走后门“,本来该先把你的事情解决完了再解决后边的人的事情,但是这时候有走后门的人,那就会停止给你解决,而优先把走后门的人事情解决了;
5.suspend() 和 resume() :这两个方法是配套使用的,suspend() 是让线程进入阻塞状态,它的解药就是resume(),没有resume()它自己是不会恢复的,由于这种比较容易出现死锁现象,所以jdk1.5之后就已经被废除了,这对就是相爱相杀的一对。
更多相关内容 -
IO为什么会阻塞?单线程与多线程阻塞IO模型
2020-10-16 11:35:34阻塞I/O在做I/O读写操作时会使当前线程进入阻塞状态,而非阻塞I/O则不进入阻塞状态。对于线程,单线程情况下由一条线程负责所有客户端连接的I/O操作,而多线程情况下则由若干线程共同处理所有客户端连接的I/O操作。 ...关于I/O模型
I/O模型是指计算机中涉及到I/O操作时使用的模型,为了解决各种模型存在的问题,人们提出了很多不同的I/O模型。与之相关的概念有线程、阻塞、非阻塞、同步以及异步等等。
对于I/O,可以分成阻塞I/O与非阻塞I/O两大类型。阻塞I/O在做I/O读写操作时会使当前线程进入阻塞状态,而非阻塞I/O则不进入阻塞状态。对于线程,单线程情况下由一条线程负责所有客户端连接的I/O操作,而多线程情况下则由若干线程共同处理所有客户端连接的I/O操作。
此外,需要注意的是计算机的I/O其实包含了各种各样的I/O,比如网络I/0、磁盘I/O、键盘I/O、鼠标I/O等等。我们这里以经典的网络I/O场景作为方向进行讲解,本节我们将讲解单线程阻塞I/O模型和多线程阻塞I/O模型。
为什么会阻塞
之所以会产生阻塞是因为程序执行I/O时一般需要从内核空间和用户空间拷贝数据,但内存空间的数据可能需要较长时间准备,这就导致了用户空间产生阻塞。应用程序处于用户空间中,对应着一个线程,线程对应着缓冲区。当我们要进行I/O操作时,需要通过内核来执行具体的操作。内核去做I/O操作,得到数据后将数据拷贝到用户空间供使用。
下面看执行网络I/O时如何产生阻塞。应用程序首先发起读取操作,然后进入阻塞状态,由操作系统内核完成I/O操作。内
-
Java线程阻塞和唤醒的几种方式
2020-12-17 10:04:09使用wait()方法来阻塞线程,使用notify()和notifyAll()方法来唤醒线程。 调用wait()方法后,线程将被阻塞,wait()方法将会释放当前持有的监视器锁(monitor),直到有线程调用notify/notifyAll()方法后方能继续执行。 ...Object类自带的方法
使用wait()方法来阻塞线程,使用notify()和notifyAll()方法来唤醒线程。
调用wait()方法后,线程将被阻塞,wait()方法将会释放当前持有的监视器锁(monitor),直到有线程调用notify/notifyAll()方法后方能继续执行。
notify/notifyAll()方法只是解除了等待线程的阻塞,并不会马上释放监视器锁,而是在相应的被synchronized关键字修饰的同步方法或同步代码块执行结束后才自动释放锁。
默认使用非公平锁,无法修改。
缺点:- 使用几个方法时,必须处于被synchronized关键字修饰的同步方法或同步代码块中,否则程序运行时,会抛出IllegalMonitorStateException异常。
- 线程的唤醒必须在线程阻塞之后,否则,当前线程被阻塞之后,一直没有唤醒,线程将会一直等待下去(对比LockSupport)
public class SynchronizedDemo { // 三个线程交替打印ABC public static void main(String[] args) { Print print = new Print(); new Thread(() -> { while (true) { print.printA(); } }, "A").start(); new Thread(() -> { while (true) { print.printB(); } }, "B").start(); new Thread(() -> { while (true) { print.printC(); } }, "C").start(); } } class Print { Object object = new Object(); int num = 1; public void printA() { synchronized (object) { try { while (num != 1) { object.wait(); } for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "==>A"); } num = 2; object.notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void printB() { synchronized (object) { try { while (num != 2) { object.wait(); } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "==>B"); } num = 3; object.notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void printC() { synchronized (object) { try { while (num != 3) { object.wait(); } for (int i = 0; i < 15; i++) { System.out.println(Thread.currentThread().getName() + "==>C"); } num = 1; object.notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Condition接口
使用await()方法来阻塞线程,signal()/singnalAll()方法来唤醒线程。
需要使用lock对象的newCondition()方法获得Condition条件对象(可有多个)。
可实现公平锁,默认是非公平锁
缺点:- 必须被Lock包裹,否则会在运行时抛出IllegalMonitorStateException异常。
- 线程的唤醒必须在线程阻塞之后
- Lock的实现是基于AQS,效率稍高于synchronized
public class ConditionDemo { // 三个线程交替打印ABC public static void main(String[] args) { Print print = new Print(); new Thread(() -> { while (true) { print.printA(); } }, "A").start(); new Thread(() -> { while (true) { print.printB(); } }, "B").start(); new Thread(() -> { while (true) { print.printC(); } }, "C").start(); } } class Print { private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); private int num = 1; public void printA() { lock.lock(); try { while (num != 1) { condition1.await(); } for (int i = 0; i < 5; ++i) { System.out.println(Thread.currentThread().getName() + "==>A"); } num = 2; condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printB() { lock.lock(); try { while (num != 2) { condition2.await(); } for (int i = 0; i < 10; ++i) { System.out.println(Thread.currentThread().getName() + "==>B"); } num = 3; condition3.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printC() { lock.lock(); try { while (num != 3) { condition3.await(); } for (int i = 0; i < 15; ++i) { System.out.println(Thread.currentThread().getName() + "==>C"); } num = 1; condition1.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
LockSupport
使用park()来阻塞线程,用unpark()方法来唤醒线程。
这里有一个许可证的概念,许可不能累积,并且最多只能有一个许可,只有1和0的区别。
特点:- 使用灵活,可以直接使用
- 线程唤醒可在线程阻塞之前,因为调用unpark()方法后,线程已经获得了一个许可证(但也只能有一个许可证),之后阻塞时,可以直接使用这个许可证来通行。
- 效率高
public class LockSupportDemo { // 三个线程交替打印ABC public static void main(String[] args) throws Exception { Print print = new Print(); Thread threadA = new Thread(() -> { while (true) { print.printA(); } }, "A"); Thread threadB = new Thread(() -> { while (true) { print.printB(); } }, "B"); Thread threadC = new Thread(() -> { while (true) { print.printC(); } }, "C"); threadA.start(); threadB.start(); threadC.start(); while (true) { LockSupport.unpark(threadA); LockSupport.unpark(threadB); LockSupport.unpark(threadC); } } } class Print { private int num = 1; public void printA() { while (num != 1) { LockSupport.park(); } for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "==>A"); } num = 2; } public void printB() { while (num != 2) { LockSupport.park(); } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "==>B"); } num = 3; } public void printC() { while (num != 3) { LockSupport.park(); } for (int i = 0; i < 15; i++) { System.out.println(Thread.currentThread().getName() + "==>C"); } num = 1; } }
-
详解Java多线程编程中LockSupport类的线程阻塞用法
2020-09-02 01:12:19LockSupport类提供了park()和unpark()两个方法来实现线程的阻塞和唤醒,下面我们就来详解Java多线程编程中LockSupport类的线程阻塞用法: -
java线程阻塞问题排查方法
2021-03-09 09:22:30我开发的worker,每隔几个月线上都会阻塞一次,一直都没查出问题。今天终于了了这个心结。把解决过程总结下和大家分享。首先用jstack命令打出这个进程的全部线程堆栈。拿到线程dump文件之后,搜索自己的worker名字。...我开发的worker,每隔几个月线上都会阻塞一次,一直都没查出问题。今天终于了了这个心结。把解决过程总结下和大家分享。
首先用jstack命令打出这个进程的全部线程堆栈。拿到线程dump文件之后,搜索自己的worker名字。
"DefaultQuartzScheduler_Worker-10" prio=10 tid=0x00007f55cd54d800 nid=0x3e2e waiting for monitor entry [0x00007f51ab8f7000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:86)
- waiting to lock <0x0000000782359268> (a com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl)
at com.jd.chat.worker.service.timer.AccountIncSyncTimer.run(AccountIncSyncTimer.java:114)
at com.jd.chat.worker.service.timer.AbstractTimer.start(AbstractTimer.java:44)
at com.jd.chat.worker.service.timer.AbstractTimer.doJob(AbstractTimer.java:49)
at com.jd.chat.worker.web.context.StartAppListener$TimerJob.execute(StartAppListener.java:188)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
- locked <0x0000000783641c68> (a java.lang.Object)
很快便找到了线程在哪一行被阻塞。但是酒瓶这么点信息,并不能查出问题的真正原因,这里推荐一个工具,叫tda.bat。同事给我的,网上应该有下载。把这个dump文件导入到tda中。找到阻塞的线程。阻塞的线程是红色的。
之所以说这个软件好,是因为当你找到blocked的线程后,界面的下方,会打出阻塞的更详细的线程堆栈。截取这个堆栈的部分信息。
at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)
at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:80)
at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteUpdate(MappedStatement.java:216)
at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:94)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:457)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90)
at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:380)
at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:1)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:200)
at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:378)
at com.jd.im.data.dataresource.ImSqlMapClientTemplate.retriedWithoutAnyInterventionUpdate(ImSqlMapClientTemplate.java:169)
at com.jd.im.data.dataresource.ImSqlMapClientTemplate.update(ImSqlMapClientTemplate.java:137)
at com.jd.chat.dao.impl.WriteDaoImpl.update(WriteDaoImpl.java:21)
at com.jd.chat.zone.service.impl.GroupServiceImpl.updateRoute(GroupServiceImpl.java:766)
at com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl.addAccounts(NewPopAccountSyncServiceImpl.java:267)
- locked <0x0000000782359268> (a com.jd.chat.worker.service.impl.NewPopAccountSyncServiceImpl)
这个才是真正有用的堆栈!它告诉了我程序是在执行SQL的时候,SQL发生死锁,于是线程被阻塞。它还提供了更有用的信息,那就是到底是哪个SQL导致的死锁。堆栈的倒数第三行指示了导致死锁的SQL。
但是一定要用这个工具才能找到具体的原因吗?答案当然是NO!
告诉大家怎么不通过工具找到阻塞的真正原因!
刚刚通过“BLOCKED”关键字搜到了线程堆栈,找到它的线程名“DefaultQuartzScheduler_Worker-10”。OK,然后,把最后的10改成1,也就是“DefaultQuartzScheduler_Worker-1”,然后再拿这个关键字搜索整个进程堆栈。
"DefaultQuartzScheduler_Worker-1" prio=10 tid=0x00007f55cd2aa000 nid=0x3e25 runnable [0x00007f51b02c0000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
- locked <0x0000000791370d50> (a java.io.BufferedInputStream)
at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:82)
at org.mariadb.jdbc.internal.common.packet.buffer.ReadUtil.readFully(ReadUtil.java:92)
at org.mariadb.jdbc.internal.common.packet.RawPacket.nextPacket(RawPacket.java:77)
at org.mariadb.jdbc.internal.common.packet.SyncPacketFetcher.getRawPacket(SyncPacketFetcher.java:67)
at org.mariadb.jdbc.internal.mysql.MySQLProtocol.getResult(MySQLProtocol.java:891)
at org.mariadb.jdbc.internal.mysql.MySQLProtocol.executeQuery(MySQLProtocol.java:982)
at org.mariadb.jdbc.MySQLStatement.execute(MySQLStatement.java:280)
- locked <0x0000000791370678> (a org.mariadb.jdbc.internal.mysql.MySQLProtocol)
at org.mariadb.jdbc.MySQLPreparedStatement.execute(MySQLPreparedStatement.java:141)
贴出这个进程堆栈的一部分。这个进程堆栈其实也就是刚刚tda软件界面下方展示的导致线程阻塞的真正的堆栈!这个线程是runnable状态的,可惜mysql是锁死的。也就是说阻塞在了mysql里。
感觉这是一个由张三的命案牵出李四的命案的故事。
-
浅谈JAVA中的线程阻塞方法
2021-02-12 10:23:12线程阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),Java 提供了大量方法来支持阻塞,下面我们来一起总结一下JAVA中实现线程阻塞的方法。线程睡眠 sleep() 方法:sleep() 允许 指定以毫秒为单位的... -
java 基础--线程阻塞的原因
2021-02-25 19:29:241. 线程在运行的过程中因为某些原因而发生阻塞,阻塞状态的线程的特点是:该线程放弃CPU的使用,暂停运行,只有等到导致阻塞的原因消除之后才回复运行。或者是被其他的线程中断,该线 程也会退出阻塞状态,同时抛出... -
java如何避免线程阻塞?相关方法解析
2021-03-09 06:52:56最近有小伙伴在工作中遇到了java线程阻塞问题,面对这样的问题,大家束手无策,不知道从何下手,那么今天我们就给大家分享一些关于java避免线程阻塞的方法。阻塞指的是暂停一个Java线程同步的执行以等待某个条件发生... -
java线程阻塞问题排查
2021-02-04 10:56:15业务线程调用是交由spring管理的,设置好频次,调用完成即结束,一般线程耗时都很少 1、获取耗时较长的线程id top -Hpjava进程ID 这个是以cpu使用高低对线程进行排序 因为这次的问题不是cpu标高,而是业务跑不... -
Java中实现线程阻塞的方法
2020-06-23 17:56:51Java中实现线程阻塞的方法线程睡眠:Thread.sleep (long millis)线程等待:Object类中的wait()方法线程礼让,Thread.yield() 方法线程自闭,join()方法 线程睡眠:Thread.sleep (long millis) 使线程转到阻塞状态。... -
网关 zuul 线程阻塞分析
2019-12-19 16:16:32网关 zuul 线程阻塞分析 本文基于一个线上真实问题。在 Zuul 无任何安全防护措施时,若遇到较大流量(单个Zuul应用在默认配置下200并发即可),将产生非常严重的后果。 本文主要是探寻下问题产生的原因,问题背景与... -
pyqt5耗时线程阻塞界面
2020-11-12 10:20:31在使用pyqt5编写UI的时候,正如参考网址1所述,我们一般会将后台任务与界面区分,但我自己在实现的时候发现即使使用后台线程,但仍然会阻塞界面的操作,类似问题在参考网址2中也有提到。通过对比我自己的代码和参考... -
Java多线程 停止线程遇到线程阻塞如何处理?
2020-08-18 08:12:49文章目录线程可能被阻塞如果线程在每次迭代时都阻塞 线程可能被阻塞 子线程sleep的过程中, 给出中断信号的demo 当子线程正在休眠的过程中, 去进行线程的中断. 因此主线程要等子线程执行到 Thread.sleep(1000);这一行... -
Log4j blocked 线程阻塞问题
2020-08-29 16:40:40于是我使用 jvm工具分析了JVM的情况,最终定位为 log4j引起的线程 blocked,不算是死锁,但是所以请求都会调用log4j,而log4j又无法正常执行,所以 所有请求都会 block。线程堆栈信息片段 形如: "qtp... -
查看是否有线程阻塞方法
2020-11-11 16:03:52ps -no pid -I THREAD,tid,time printf “%x\n” 线程pid (转换成16进制) jstack pid|grep b32 -A 30 (pid为进程号,b32为线程转换后16进制字符) -
C#多线程进阶一(线程阻塞和任务延续,线程取消,线程返回值,多线程中的异常处理)
2020-05-26 15:32:031. 线程阻塞和任务延续 (1)主线程等待一个或多个子线程执行完后再执行(或者)等待多个子线程中任何一个任务完成再执行 (2)某个子线程等待一个或多个子线程执行完后再执行(或者)等待多个子线程中任何... -
Java中什么方法导致线程阻塞
2018-03-24 16:45:41一、为什么引入线程阻塞机制? 为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问... -
什么导致线程阻塞?
2019-07-25 13:07:14导致线程阻塞的原因主要有以下几方面。 1、线程进行了休眠:线程执行了Thread.sleep(int n)方法,线程放弃CPU,睡眠n毫秒,然后恢复运行。 2、线程等待获取同步锁才能进行下一步操作:线程要执行一段同步代码,由于... -
Java 线程阻塞、中断及优雅退出
2018-07-18 20:39:44本文转自:Java 线程阻塞、中断及优雅退出 线程阻塞 一个线程进入阻塞状态的原因可能如下(已排除Deprecated方法): sleep() sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前... -
线程阻塞的实现原理
2018-10-13 13:54:06Java中,当多个线程同时请求独占锁时,JVM虚拟机会根据上一次获取锁操作中对锁的持有时间来决定是挂起线程还是让线程自旋,当上一次持有锁的时间相对较长时,会将线程加入阻塞队列,否则让线程通过while来自旋。... -
C# 多线程阻塞和继续
2020-07-13 09:16:00运用ManualResetEvent类来对线程进行堵塞和持续操作。 它有三个重要的办法:Reset、Set和WaitOne。 1、首先介绍一下它的构造函数: publicManualResetEvent(boolinitialState); 参数initialState,假如为true,... -
【Java并发编程】Java多线程(二):多线程一定好吗?线程阻塞时占用CPU吗?
2020-09-14 20:09:30而使用多线程,当一些线程发生阻塞的时候,另一些线程则仍能利用CPU,而不至于让CPU一直空闲。 利用CPU的多核并行计算能力 现在的CPU基本上都是多核的。使用多线程,可以利用多核同时执行多个线程,而不至于单线程时... -
java处理线程阻塞的小技巧
2017-11-29 14:27:04在java中我们使用多线程去处理一些业务,如果业务比较复杂且当并发量有挺大的时候,很有可能出现线程阻塞的问题。案例: 有一个触发接口,根据触发的信息内部开启多个线程去执行业务,每个线程都会去执行两种业务:... -
线程阻塞机制
2019-04-19 12:03:50一、为什么引入线程阻塞机制 为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,... -
linux系统排查线程阻塞问题
2018-08-04 17:04:41问题引入:在工作中会遇到某个程序占用cpu高或者不响应请求等问题,对于这类问题的排查首先考虑程序中是不是有线程阻塞。 首先,使用ps查看程序的进程号。 [root@Joe ~]# ps -ef|grep ProgramName root 11694 ... -
线程阻塞方法
2018-03-29 13:55:54//忍让一段时间wait方法:当调用wait方法后,当前线程会释放持有的monitor对象锁,因此,其他线程还可以进入到同步方法,线程被唤醒后(如果加时间参数的话,则会在时间被消耗后唤醒,否则需要通过notify或notifyall... -
Java线程 - sleep()和wait()方法的区别, 线程阻塞BLOCKED和等待WAITING的区别
2019-02-26 11:44:39二、线程阻塞BLOCKED和等待WAITING的区别 阻塞BLOCKED 等待WAITING 不知羞耻的摘录 一、 sleep()和wait()方法的区别 sleep()方法 sleep()方法是Thread类的方法,通过其定义可知是个native方法,在指定的时间... -
一个线程阻塞引起的超时问题
2017-08-27 11:38:36接着开始怀疑负责服务端与客户端处理的线程阻塞了,但是仅仅从debug代码去分析,没办法定位问题,在分析着eventloop执行的动作时也没有找到非常耗时的任务,所以这个点在无法定位的情况下,只能暂时先搁置了,转去...