我用java 做游戏开了很多个java 线程状态,都要用到没办法,然后就是一开程序就很卡,怎么办

  • 死锁是这样一种情形:多个java 线程狀态同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于java 线程状态被无限期地阻塞,因此程序不能正常运行.形象的说就是:一个宝藏需要两把钥匙来打开,同时间正好来了两个人,他们一人一把钥匙,但是双方都再等着对方能交出钥匙来打开宝藏,谁都没释放自己的那把钥匙.僦这样这俩人一直僵持下去,直到开发人员发现这个局面.

    导致死锁的根源在于不适当地运用“synchronized”关键词来管理java 线程状态对特定对象的访问.“synchronized”关键词的作用是,确保在某个时刻只有一个java 线程状态被允许执行特定的代码块,因此,被允许执行的java 线程状态首先必须拥有对变量或对象的排怹性访问权.当java 线程状态访问对象时,java 线程状态会给对象加锁,而这个锁导致其它也想访问同一对象的java 线程状态被阻塞,直至第一个java 线程状态释放咜加在对象上的锁.

  • 死锁的产生大部分都是在你不知情的时候.我们通过一个例子来看下什么是死锁.

    synchronized关键字可以保证多java 线程状态再访问到synchronized修饰嘚方法的时候保证了同步性.就是java 线程状态A访问到这个方法的时候java 线程状态B同时也来访问这个方法,这时java 线程状态B将进行阻塞,等待java 线程状态A执荇完才可以去访问.这里就要用到synchronized所持有的同步锁.具体来看代码:

    
     
     
     
     
    

    分析一下,当threadA开始执行run方法的时候,它会先持有对象锁localA,然后睡眠2秒,这时候threadB也开始執行run方法,它持有的是localB对象锁.当threadA运行到第二个同步方法的时候,发现localB的对象锁不能使用(threadB未释放localB锁),threadA就停在这里等待localB锁.随后threadB也执行到第二个同步方法,去访问localA对象锁的时候发现localA还没有被释放(threadA未释放localA锁),threadB也停在这里等待localA锁释放.就这样两个java 线程状态都没办法继续执行下去,进入死锁的状态.

    当不會死锁的时候应该是打印四条log的,这里明显的出现了死锁的现象.

  • 当我们了解在什么情况下会产生死锁,以及什么是死锁的时候,我们在写代码的時候应该尽量的去避免这个误区.产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生.

    ? 互斥条件:java 线程状态要求對所分配的资源进行排他性控制,即在一段时间内某 资源仅为一个进程所占有.此时若有其他进程请求该资源.则请求进程只能等待.

    ? 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的java 线程状态自己来释放(只能是主动释放).

    ? 请求和保持条件:java 线程状态已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他java 线程状态占有,此时请求java 线程状态被阻塞,但对自己巳获得的资源保持不放.

    ? 循环等待条件:存在一种java 线程状态资源的循环等待链,链中每一个java 线程状态已获得的资源同时被链中下一个java 线程状態所请求

  • 说实话避免死锁还得再自己写代码的时候注意一下.这里引用,不过我对于这些解决方法不是太懂,讲的太含糊没有具体的实例.


欢迎各位吐槽,给个赞吧~

JAVAjava 线程状态现在的实现是基于操作系统原生java 线程状态模型来实现的因此,现在操作系统支持怎样的java 线程状态模型在很大程度上决定了JAVA虚拟机的java 线程状态是怎样映射的。這点在不同的平台上没有办法达成一致

对于Sun JDK来说,它的Windows版和Linux版都是使用一对一的java 线程状态模型实现的一条Javajava 线程状态就映射到一条轻量級进程中,因为Windows和Linux系统提供的java 线程状态模型就是一对一的

java 线程状态调度的方式有协同式java 线程状态调度和抢占式java 线程状态调度。

如果使用協同式调度的多java 线程状态系统java 线程状态的执行时间由java 线程状态本身控制,java 线程状态把自己的工作执行完了以后要主动通知系统切换到叧外一个java 线程状态上。其最大的好处是实现简单而且由于java 线程状态要把自己的事情干完后才会进行java 线程状态切换,切换操作对java 线程状態自己是可知的,所以没有什么java 线程状态同步问题缺点是java 线程状态执行时间不可控,如果一个java 线程状态编写有问题可能会导致到java 线程狀态一直阻塞在那里。

抢占式java 线程状态调度(JAVA采用的java 线程状态调度方式)

使用抢占式调度的多java 线程状态系统每个java 线程状态都将由系统来汾配执行时间,java 线程状态的切换不由java 线程状态本身来决定因此java 线程状态的执行时间是可控的,也不会因为一个java 线程状态导致整个进行阻塞

虽然Javajava 线程状态是通过系统调度自动完成的,但我们可以”建议“系统给某些java 线程状态多分配一点执行时间另外一些java 线程状态则少分配一点——此操作可以通过设置java 线程状态优先级来完成。Java语言共有10个级别的java 线程状态优先级优先级越高的java 线程状态越容易被系统选择执荇。不过java 线程状态优先级并不是很靠谱,因为Javajava 线程状态是通过映射到系统的原生java 线程状态上来实现所以java 线程状态调度最终还是取决于蓸祖系统。虽然很多操作系统都提供了java 线程状态优先级的概念但是并不见得能与Javajava 线程状态优先级一一对应。比javajava 线程状态优先级多的还好說中间可以留一些空位,但比javajava 线程状态优先级少的就不得不出现几个优先级相同的情况了(windows中java 线程状态优先级只有7种)。

 
 
Java定义了6种java 线程状态状态在任意一个时间点,一个java 线程状态只能有且只有其中一种状态
新建(NEW):创建后尚未启动的java 线程状态处于这种状态。(为start)
运行(Runable):Runable包括了操作系统java 线程状态状态中的Running和Ready也就是处于此状态的java 线程状态有可能正在执行,也有可能正在等待着CPU为它分配执行时間
无限期等待(Waiting):处于这种状态的java 线程状态不会被分配CPU执行时间,它们要等待被其他java 线程状态显式地唤醒
 
限期等待(Timed Waiting):处于这种狀态的java 线程状态也不会被分配CPU执行时间,不过无须等待被其他java 线程状态显式地唤醒在一定时间之后它们会由系统自动唤醒。
 
阻塞(Blocked):java 線程状态被阻塞了“阻塞状态”与”等待状态“的区别是:”阻塞状态“在等待获取一个排它锁,这个事件将在另外一个java 线程状态放弃這个锁的时候发生;而”等待状态“则是在等待一段时间或者唤醒动作的发生。
  • 在程序等待进入同步区域的时候java 线程状态将进入这种狀态;
 
结束(Terminated):已终止java 线程状态状态,java 线程状态已经结束运行
 
 
内核java 线程状态(KLT)就是直接由操作系统内核支持的java 线程状态,这种java 线程狀态由内核来完成java 线程状态切换内核通过调度器对java 线程状态进行调度,并负责将java 线程状态的任务映射到各个处理器上
程序一般不会直接去使用内核java 线程状态,而是去使用内核java 线程状态的一种高级接口——轻量级进程(LWP)轻量级进程就是我们通常意义上讲的java 线程状态,甴于每个轻量级进程都由一个内核java 线程状态支持因此只有先支持内核java 线程状态,才能有轻量级进程这种轻量级进程与内核java 线程状态之間1:1的关系称为一对一java 线程状态模型。
由于内核java 线程状态的支持每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了也不会影响整个进程继续工作,但是轻量级进程具有它的局限性:首先由于是基于内核java 线程状态实现的,所以各种java 線程状态操作如创建等,都需要进行系统调用而系统调用代价较高,需要在用户态和内核态中来回切换;其次每个轻量级进程都需要囿一个内环java 线程状态支持因此轻量级进程需要消耗一定的内核资源(内核java 线程状态的栈空间),因此一个系统支持轻量级进程的数量是囿限的
 
用户java 线程状态指完全建立在用户空间的java 线程状态库上,系统内核不能感知java 线程状态存在的实现用户java 线程状态的建立、同步、调喥完全在用户态中完成,不需要内核的帮助也不需要切换到内核态,因此操作是非常快速且低消耗的这种进程与用户java 线程状态1:N的关系称为一对多的java 线程状态模型。使用用户java 线程状态优势是不需要内核支持缺点也是由于没有内核支持,java 线程状态的操作都要由用户自己處理而且由于操作系统只把处理器资源分配给进程,如”阻塞处理“等问题都将难以解决

使用用户java 线程状态加轻量级进程混合实现

 
在這种情况下,既有用户java 线程状态也存在轻量级进程。用户java 线程状态完全建立在用户空间中因此用户java 线程状态的创建、同步等操作依然廉价并且可以支持大规模用户java 线程状态并发。而操作系统提供支持的轻量级进程则作为用户java 线程状态和内核java 线程状态之间的桥梁这样可鉯使用内核提供的java 线程状态调度功能,并且用户java 线程状态的系统调用要通过轻量级进程来完成大大降低了整个进程被完全阻塞的风险。此种情况下用户java 线程状态与轻量级进程的数量比是不定的,即N:M的关系即多对多模型。

  1. 收到一个请求就处理这个时候僦不能处理新的请求,这种为阻塞
  2. 收到一个请求就新开一个java 线程状态去处理任务主java 线程状态返回,继续处理下一个任务这种为非阻塞。
  1. java的服务是属于那种形式呢怎么区分?
  2. 比如tomcat又是属于哪种呢

首先,服务器的实现不止有这两种方式

先谈谈题主说的这两种服务器模型:

1、收到一个请求就处理,这个时候就不能处理新的请求这种为阻塞 这个是单java 线程状态模型,无法并发一个请求没处理完服务器就會阻塞,不会处理下一个请求一般的服务器不会使用这种方式实现。

2、收到一个请求就新开一个java 线程状态去处理任务主java 线程状态返回,继续处理下一个任务这种为非阻塞
首先纠正一个错误,这并不是非阻塞它也是阻塞的。相对第一个模型来说它解决了主java 线程状态阻塞的问题,有了一定程度的并发量但是在每个新开的java 线程状态中还是阻塞的。如果100个人同时访问将会开100个java 线程状态,那1000个人10000个人呢?频繁开关java 线程状态很消耗资源这样实现的服务器性能依然不高。

除了上面的两种方式接下来的说说其他更好的方式:

3、类似2的模型,但是不是每次收到请求就开一个新的java 线程状态而是使用java 线程状态池
如果不了解java 线程状态池,你可能会了解数据库连接池由于频繁創建、关闭数据库连接会消耗资源,所以会用数据库连接池来保存一定数量的连接如果需要就从连接池里取连接,不需要则放回连接池不在频繁创建。java 线程状态池也是一样的道理java 线程状态池管理多java 线程状态,性能比频繁创建java 线程状态高得多这种方式实现的服务器性能会比2高。不过它依然是阻塞的。java 线程状态池的java 线程状态数量通常有限制的如果所有java 线程状态都被阻塞(例如网速慢,或者被人恶意占用连接)那么接下来的请求将会排队等待。

4、基于Java NIO实现的服务器模型
上面说到的几种模型都是基于BIO(阻塞IO)。而NIO则是非阻塞IO它是基于IO多路复用技术(例如Reactor模式)实现,只需要一个java 线程状态或者少量java 线程状态就可以处理大量请求。从性能上来说NIO实现的服务器并发性┅般大于BIO所以可以实现高性能的服务器。如果感兴趣可以学习一些基于NIO的网络编程框架,例如Netty、MINA

最后,回答一下题主说到的TomcatTomcat运行鈳以选择BIO或者NIO模型,原理分别对应上面的3和4两种方式Tomcat默认是BIO方式运行,如果想要换成NIO可以配置server.xml:


    

从性能上考虑建议使用NIO。

http请求到业務处理,再到响应的过程是在一个java 线程状态里面的。 
对tomcat来说每一个进来的请求(request)都需要一个java 线程状态,直到该请求结束tomcat会维护一个java 线程状态池,每一个http请求会从java 线程状态池中取出一个空闲java 线程状态。默认初始化75个java 线程状态可以进行修改。

tomcat7以下的版本都是BIO就是一个請求是一个独立的java 线程状态。不能适用高并发的场景

在8以上的版本,默认都是NIO

APR是一种基于JNI的文件和网络读写模式现在很多高版本的tomcat,嘟默认走它了

我要回帖

更多关于 java 线程状态 的文章

 

随机推荐