java程序是多线程的
为什么说java程序是多线程的呢?
直接看下面这个简单的main方法,粗略一看好像并没有启动其他线程,但是实际结果并非如此。
package com.su.mybatis.oracle.controller;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
public class Main {
public static void main(String[] args) {
//Java 虚拟机线程系统的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor和synchronizer信息,仅仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
// 遍历线程信息,仅打印线程ID和线程名称信息
for (ThreadInfo threadInfo : threadInfos) {
System.out.println(threadInfo.getThreadId() + "--" + threadInfo.getThreadName());
}
}
}
输出结果:
5--Attach Listener //内存dump,线程dump,类信息统计,获取系统属性等
4--Signal Dispatcher //分发处理发送给JVM信号的线程
3--Finalizer //调用对象finalize方法的线程
2--Reference Handler //清除Reference的线程
1--main //main线程,用户程序入口
上面输出结果明确地说明了只执行一个简单的main方法,但是jdk启动了5个线程来执行,因此,java程序是多线程的。值得注意的是,main方法开始执行才会生成这几个线程,但是它们都是平等的。
线程的优先级
线程的优先级范围1~10,默认优先级为5。理论上来说,优先级越高,能获得更多的时间片分配,可以适当给需要更多时间片的线程(I/O操作)设置更高的优先级,但是这也不是必然的,操作系统也可能忽略线程的优先级。
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) throws InterruptedException {
TestThread t = new TestThread();
t.start();
}
}
class TestThread extends Thread{
@Override
public void run() {
Thread currentThread = Thread.currentThread();//当前线程
System.out.println("线程名称:" + currentThread.getName());
System.out.println("线程优先级:" + currentThread.getPriority());
}
}
运行结果:
线程名称:Thread-0
线程优先级:5
设置线程名称和优先级,运行
public static void main(String[] args) throws InterruptedException {
TestThread t = new TestThread();
t.setName("TestThread");//线程名字
t.setPriority(10);//优先级 1~10
t.start();
}
运行结果:
线程名称:TestThread
线程优先级:10
守护线程
守护线程是一种程序运行时,在后台调度提供支持性服务的线程。当非守护线程都结束时,jdk会强制关闭所有守护线程,jvm会退出,这也就意味着守护线程里面有可能不会进行资源回收。垃圾回收线程就是守护线程。
设置方式:
TestThread t = new TestThread();
t.setDaemon(true);//true:守护线程
线程的实现方式
打开Thread.class,类描述明确说明创建线程有且只有两种方式:继承Thread类和实现Runable接口
1)、继承Thread类
package com.su.mybatis.oracle.controller;
public class TestThread extends Thread{
@Override
public void run() {
//TODO
System.out.println("1111111111");
}
}
2)、实现Runable接口
package com.su.mybatis.oracle.controller;
public class TestRunnable implements Runnable{
@Override
public void run() {
//TODO
System.out.println("2222222222");
}
}
线程启动
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) {
TestThread t1 = new TestThread();
t1.start();
TestRunnable t2 = new TestRunnable();
new Thread(t2).start() ;
}
}
运行结果:
1111111111
2222222222
注意:线程调用start()方法时会校验线程状态,如果线程已经调用过start()方法,会抛出java.lang.IllegalThreadStateException。
同一个线程调用两次start()的方法如下所示:
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) {
TestThread t1 = new TestThread();
t1.start();
t1.start();
}
}
上面方法会抛出异常,因为start()中对线程状态校验:
if (threadStatus != 0)
throw new IllegalThreadStateException();
Thread与Runnable的区别
准确来说,Thread才是Java里对线程的唯一抽象,Runnable只是对任务(业务逻辑)的抽象。Thread可以接受任意一个Runnable的实例并执行。
举个例子:周末,你在打游戏,你女朋友在追剧;快到饭点了,你女朋友做饭,你帮忙切菜;你们吃完饭后,一起去看电影.....那么在这个例子中,你和你女朋友都可以看成是一个Thread,而打游戏、追剧、做饭、切菜、吃饭、看电影等这些都可以看成是一个Runnable。Thread可以接受任意一个Runnable的实例并执行意味着你可以去追剧,你女朋友可以去打游戏等等。
线程中止
1)、自然终止
线程执行完;
抛出异常提前结束。
2)、suspend()、stop()
suspend(),线程进入睡眠状态,需要等待唤醒,但是会占据资源,会造成死锁问题;
stop(),强制终止线程,不能保证占据资源正常释放,比如,上传图片过程中使用了stop()会导致图片损坏。
因为以上方法的特性,所有不建议使用上述方法,jdk中这些方法都是过期的。
3)、安全中止
interrupt(),修改中断线程标志位为true,对线程中断,但是并不是强制的,也就是说这个方法只是通知线程需要中断,实际上线程可以不理会中断请求而继续执行;
isInterrupted(),检查线程标志位,true:线程被中断,false:线程不被中断;
Thread.interrupted(),与isInterrupted()作用相同,但是会将中断标志位改为false。
举个例子:
Main.java
package com.su.mybatis.oracle.controller;
public class Main {
public static void main(String[] args) throws InterruptedException {
TestThread t1 = new TestThread();
t1.start();
TestThread.sleep(10);//保证线程在while中运行一段时间
t1.interrupt();//设置线程中断标志位true
}
}
TestThread .java
package com.su.mybatis.oracle.controller;
public class TestThread extends Thread{
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("1-线程(" + threadName + ")中断标志:" + isInterrupted());
while(true){//--判断标志1
// while(!isInterrupted()){//--判断标志2
// while(!Thread.interrupted()){//--判断标志3
System.out.println("------");
System.out.println("2-线程(" + threadName+")中断标志:" + isInterrupted());
}
// System.out.println("3-线程(" + threadName+")中断标志:" + isInterrupted());
}
}
当TestThread.java中while使用判断标志1时,启动Main.java中的main方法,会发现虽然将线程得中断标志位设置为true,但是while中的打印并不会停止,线程并没有理会中断请求而继续执行;
------
2-线程(Thread-0)中断标志:true
------
2-线程(Thread-0)中断标志:true
.
.
.
当while使用判断标志2时,加上‘3-线程...’的打印(删除前面的//),启动main方法,一段时间后,线程中止,控制台输出如下:
1-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
.
.
.
------
2-线程(Thread-0)中断标志:true
3-线程(Thread-0)中断标志:true
当while使用判断标志3时,加上‘3-线程...’的打印,启动main方法,一段时间后,线程中止,控制台输出如下:
1-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
.
.
.
------
2-线程(Thread-0)中断标志:true
3-线程(Thread-0)中断标志:false
中断异常
sleep()、wait()、join()等方法,会抛出中断异常,把中断标志位会由true改成false,所以在中断异常中需要手动中断,为了避免关闭线程时,没有释放资源。
注意:处于死锁状态的线程是无法被中断的。
如果有写的不对的地方,请大家多多批评指正,非常感谢!