jvm 重启 执行了一半的jvm 最大线程数 怎么办

Java多线程之当一个线程在执行死循环时会影响另外一个线程吗?_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Java多线程之当一个线程在执行死循环时会影响另外一个线程吗?
来源:Linux社区&
作者:hapjin
一,问题描述
假设有两个线程在并发运行,一个线程执行的代码中含有一个死循环如:while(true)....当该线程在执行while(true)中代码时,另一个线程会有机会执行吗?
二,示例代码(代码来源于互联网)
public class Service {& & Object object1 = new Object();
& & public void methodA() {& & & & synchronized (object1) {& & & & & & System.out.println("methodA begin");& & & & & & boolean isContinueRun =& & & & & & //在这里执行一个死循环& & & & & & while (isContinueRun) {& & & & & & & & & & & & & & }& & & & & & System.out.println("methodA end");& & & & }& & }
& & Object object2 = new Object();
& & public void methodB() {& & & & synchronized (object2) {& & & & & & System.out.println("methodB begin");& & & & & & System.out.println("methodB end");& & & & }& & }}
两个线程类的实现如下:
import service.S
public class ThreadA extends Thread {
& & private S
& & public ThreadA(Service service) {& & & & super();& & & & this.service =& & }
& & @Override& & public void run() {& & & & service.methodA();& & }
线程A执行methodA(),methodA()中有一个死循环
import service.S
public class ThreadB extends Thread {
& & private S
& & public ThreadB(Service service) {& & & & super();& & & & this.service =& & }
& & @Override& & public void run() {& & & & service.methodB();& & }
线程B执行methodB(),当线程A进入methodA()中的while死循环时,线程B的能不能执行完成?
import service.Simport extthread.ThreadA;import extthread.ThreadB;
public class Run {
& & public static void main(String[] args) {& & & & Service service = new Service();
& & & & ThreadA athread = new ThreadA(service);& & & & athread.start();
& & & & ThreadB bthread = new ThreadB(service);& & & & bthread.start();& & }
执行结果:
由于线程A和线程B获得的对象锁不是同一把锁,从结果中可以看出,线程B是可以执行完成的。而线程A由于进入了while死循环,故线程A一直执行运行下去了(整个程序未结束),但线程B会结束。
也就是说,尽管线程A一直在while中执行,需要占用CPU。但是,线程的调度是由JVM或者说是操作系统来负责的,并不是说线程A一直在while,然后线程B就占用不到CPU了。
如果把Service.java修改成如下:
public class Service {//& & Object object1 = new Object();
& & public void methodA() {& & & & synchronized (this) {& & & & & & System.out.println("methodA begin");& & & & & & boolean isContinueRun =& & & & & & //在这里执行一个死循环& & & & & & while (isContinueRun) {& & & & & & & & & & & & & & }& & & & & & System.out.println("methodA end");& & & & }& & }
//& & Object object2 = new Object();
& & public void methodB() {& & & & synchronized (this) {& & & & & & System.out.println("methodB begin");& & & & & & System.out.println("methodB end");& & & & }& & }}
若线程A先获得对象锁时,由于while循环,线程A一直在while空循环中。而线程B也因为无法获得锁而执行不了methodB()。
可以看出,如果在一个线程在synchronized方法中无法退出,无法将锁释放,另一个线程就只能无限等待了。
本文永久更新链接地址:
相关资讯 & & &
& (05月02日)
& (04月03日)
& (05月17日)
& (04月13日)
& (04月03日)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
JVM详细讲解.doc60页
本文档一共被下载:
次 ,您可免费全文在线阅读后下载本文档
文档加载中...广告还剩秒
需要金币:100 &&
你可能关注的文档:
··········
··········
Java虚拟机的堆被分为3个称为generation的主要部分,它们对应于对象的生存期,如图2所示。3个generation分别是Young、Tenured和Perm,标记为Virtual的部分被保留,在必要时才实际分配出去。
Young generation由Eden和两个survivor空间组成。新对象通常创建于Eden中。其中一个survivor空间会随时被清空,并用作另一个survivor空间的目的地。当进行垃圾收集时,所有来自Eden和survivor空间的活动对象都被复制到另一个survivor空间。对象在两个survivor空间之间移动,直到它们足够“老”,能够被移入保存生存期较长对象的tenured generation中。
图2. Java虚拟机内存的结构
Perm generation保存那些在虚拟机的整个生存期都生存的对象。因此,该generation不需要被垃圾收集程序清空。
Java垃圾收集策略
除了默认的垃圾收集程序,还对其他的两个收集程序,Parallel收集程序和Concurrent Mark and Sweep收集程序(后面称为Concurrent收集程序)进行了评估。在标准的Sun Java运行时环境中,这些收集程序都可用。通常在进行垃圾收集时,虚拟机会暂停,让垃圾收集程序执行它的工作。Parallel收集程序会产生多个垃圾收集线程,以加速任务的执行并将垃圾收集暂停时间降至最短。该收集程序负责整理Young generation。Concurrent收集程序则负责整理tenured generation,而且会部分地与应用程序并发运行。虽然仍然需要完整的垃圾收集周期,但是整个周期会因之而缩短――虽然这是以牺牲少量处理能力为代价的,这些处理能力本来是可以由应用程序使用的。
这两个收集程序可以一起使用,因为它们负责的是不同的generation。这将显著缩短由垃圾收集所引发的暂停时间,如图3所示。
图3. 可用的垃圾收集程序
垃圾收集程序设置的优化
由于改变参数后的
正在加载中,请稍后...使用UncaughtExceptionHandler重启线程 - ImportNew
| 标签: ,
使用UncaughtExceptionHandler重启线程
我们已经知道,Java中有两种异常,即已检测异常和未检测异常。已检测的异常必须在抛出语句(throws clause)的方法中指定或者捕获。未检测的异常不需要指定或捕获。因为run()方法不接受抛出语句,所以当一个检测的异常在一个Thread对象的 run()方法中抛出,我们需要对其进行捕获并做相应的处理。但是当一个未检测的异常在一个线程的run()方法中抛出,默认的行为是将堆栈跟踪信息写到 控制台中(或者记录到错误日志文件中)然后退出程序。
幸运的是,Java为我们提供了一个机制,用来捕获并处理在一个线程对象中抛出的未检测异常,以避免程序终止。我们可以通过UncaughtExceptionHandler来实现这种机制。
让我们来做个UncaughtExceptionHandler的使用 示例。在这个例子中,我们已经创建一个线程,这个线程尝试解析一些本来应该是整数的字符串。我们已经写出run()方法,让它在执行时抛出 java.lang.NumberFormatException。当程序不去捕获异常时,异常经过JVM的同时线程也被杀死。这确实属于正常的行为,但 不是我们希望看到的。
不使用UncaughtExceptionHandler
在现实生活的应用中,对于一个关键的任务,虽然已经失败了几次,但是你依然愿意尝试再执行几次。下面的例子解释了这个用例,首先不使用UncaughtExceptionHandler时,线程在执行失败之后立即终止。
class Task implements Runnable
public void run()
System.out.println(Integer.parseInt(&123&));
System.out.println(Integer.parseInt(&234&));
System.out.println(Integer.parseInt(&345&));
System.out.println(Integer.parseInt(&XYZ&)); //This will cause NumberFormatException
System.out.println(Integer.parseInt(&456&));
DemoThreadExample.java
public class DemoThreadExample
public static void main(String[] args)
Task task = new Task();
Thread thread = new Thread(task);
thread.start();
下面是线程运行时的输出:
Exception in thread &Thread-0& java.lang.NumberFormatException: For input string: &XYZ&
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source)
使用UncaughtExceptionHandler之后
首先,我们实现UncaughtExceptionHandler接口,用来捕获运行时的任意未检测的异常。
ExceptionHandler.java
class ExceptionHandler implements UncaughtExceptionHandler
public void uncaughtException(Thread t, Throwable e)
System.out.printf(&An exception has been capturedn&);
System.out.printf(&Thread: %sn&, t.getId());
System.out.printf(&Exception: %s: %sn&, e.getClass().getName(), e.getMessage());
System.out.printf(&Stack Trace: n&);
e.printStackTrace(System.out);
System.out.printf(&Thread status: %sn&, t.getState());
new Thread(new Task()).start();
将异常处理程序添加到线程:
class Task implements Runnable
public void run()
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
System.out.println(Integer.parseInt(&123&));
System.out.println(Integer.parseInt(&234&));
System.out.println(Integer.parseInt(&345&));
System.out.println(Integer.parseInt(&XYZ&)); //This will cause NumberFormatException
System.out.println(Integer.parseInt(&456&));
再次运行上面的例子,会发现线程能够持续执行。实际上,如果线程完成了任务,那么它在退出时不会抛出任何异常,从而完成自身生命周期。
An exception has been captured
Thread: 1394
Exception: java.lang.NumberFormatException: For input string: &XYZ&
Stack Trace:
java.lang.NumberFormatException: For input string: &XYZ&
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
An exception has been captured
Thread: 1395
Exception: java.lang.NumberFormatException: For input string: &XYZ&
Stack Trace:
java.lang.NumberFormatException: For input string: &XYZ&
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
上面的程序实现帮你运行一个线程,在完成任务之前,这个线程会持续运行。通过其他多线程的思想同样可以实现这种情况。
请注意:UncaughtExceptionHandler可以在无需重启线程的条件下,将日志记录变得更加健壮,因为默认日志在线程执行失败时,不会提供足够的上下文信息。
学习愉快!
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
什么都不想说;新浪微博:
欢迎各位一起学习 学习群里有相关面试资料 前面625中间783后面520
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2017 ImportNewJava中的main线程是不是最后一个退出的线程 - 哥墨迹的iteye - ITeye博客
博客分类:
个人blog原文地址:
之所以写这篇文章,是因为上次被人问到这么一个问题:“在main函数里启动一个定时器,是不是main函数执行完整个程序就退出了,包括那个定时器”。多说无益,直接写个程序测试一下就知道了。
public class MainThreadTest {
public static void main(String[] args) {
new Timer().schedule(new TimerTask(){
public void run() {
System.out.println("Timer thread is running...");
}, 500, 500);
System.out.println("Main thread ends!");
然后你就会发现执行结果是这样的:
引用
Main thread ends!
Timer thread is running...
Timer thread is running...
Timer thread is running...
这至少说明main函数执行完毕之后,定时器依旧在运行,那么main线程是否退出了呢?我想不少同学可能会和我之前一样脑补这样的逻辑:“timer线程是main线程创建的,main线程会等到自己创建的所有线程都退出后才会退出”,现实当中我们有时真的会被一些自己妄自推断的结论给弄得雨里雾里,最好的做法是在自己产生一个想法之后想办法去证明它或者证否它。回到这个例子,实际上,当前有哪些线程在运行,我们是可以看到的。怎么看?用java自带的工具jstack就能看到,jstack的使用方法就不多说了,请自行搜索。通过jstack我们可以把jvm当前的线程状态dump下来,在dump结果里你会看到很多陌生的线程,这都没关系,你只需要关注下面的两个线程就好。
引用
"Timer-0" prio=6 tid=0x01b8f800 nid=0x1330 in Object.wait() [0x0c10f000..0x0c10f
be8]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on &0x03bcdd18& (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked &0x03bcdd18& (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
"main" prio=6 tid=0x nid=0x4b8 at breakpoint[0x003bf000..0x003bfe24]
java.lang.Thread.State: RUNNABLE
at me.gemoji.www.test.MainThreadTest.main(MainThreadTest.java:18)
上面的线程状态是我在main函数中加断点后运行看到的结果,你会看到这时候main线程肯定是还存在的,而且可以明确地看到它处于”at breakpoint”的状态。那么要是我让main函数继续执行下去呢?你会发现main线程不见了,而定时器的线程依旧在运行,这就充分证明main线程在main函数执行完之后就退出了,并不是最后一个退出的线程。
上面是通过实践得出的结论,下面补充一下理论。stackoverflow上有个类似的问题:,把里面的答案总结一下,基本上就这么三句话:
JVM会在所有的非守护线程(用户线程)执行完毕后退出;
main线程是用户线程;
仅有main线程一个用户线程执行完毕,不能决定JVM是否退出,也即是说main线程并不一定是最后一个退出的线程。
关于守护线程的相关知识,大家可以自行搜索下,另外,如果你对jstack打印的结果中的其他线程感兴趣,可以参考。
浏览: 85511 次
来自: 北京
whxiyi100829 写道使用import pyhdfs没 ...
luxury_zh 写道最后一点不明白,为什么每次还要对队列进 ...
最后一点不明白,为什么每次还要对队列进行排序,循环N次,调用p ...
楼主这种探索精神值得学习
我想请问一下楼主,如果不遵守robot.txt协议。那势必会找 ...

我要回帖

更多关于 jvm 线程 的文章

 

随机推荐