- 如何开启线程
开启线程2种方式:
自定义类继承Thread类,重写run方法;new 自定义类().start()
自定义类实现Runnable接口,实现run方法;new Thread(new 自定义类()).start()
- Thread和Runable
Thread是对线程的抽象封装,完成独立完成某个任务的调度,包括任务的开始、暂停、结束等操作。本身是实现Runnable接口,所以具有Runnable的所有功能。
Runnable 是对任务的抽象封装,业务任务的具体逻辑封装。本身不具有独立资源调度。需要Thread协助完成,这也就是前面说的开启线程需要先new Thread() 通过参数把Runnable传递进去。
- JVM开启,默认开启哪些线程(JDK1.8为例)
public static void main(String[] args) {
//虚拟机线程系统的管理接口(JVM开启的线程);对JVM系统进行监控时,使用类ManagementFactory
ThreadMXBean threadMXBean= ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos){
System.out.println("["+threadInfo.getThreadId()+"]"+threadInfo.getThreadName());
}
/* 一般项目启动会启动的线程有:
* [8]JDWP Command Reader
[7]JDWP Event Helper Thread
[6]JDWP Transport Listener: dt_socket
[5]Attach Listener
[4]Signal Dispatcher
[3]Finalizer 线程管理Object finalize()方法,每个对象销毁时都会调用这个方法;不推荐在这个方法中写资源释放,有时调用不到(main结束这个线程也就没有了)
[2]Reference Handler
[1]main 主线程,线程关闭其他线程会依次关闭
* */
}
- stop/interrupt/sleep等方法总结
stop():结束线程,比较野蛮会立即结束线程。比如当前线程正在写一个文件,或者正在写入数据库,正在完成一半任务时,接到stop命令,立即线程结束,导致文件不完整,错误的文件或数据库数据不完整等问题。所以JDK1.8之后不在推荐使用。当然如果能够保证当前线程没有这些类似任务,采用stop停止线程也是可以的。
interrupt():标记线程状态为中断状态(线程本身并不会结束),此时线程中如果有join、wait、sleep等方法调用的时候会抛出异常java.lang.InterruptedException。在线程的run()方法中我们需要自己写逻辑结束线程。isInterrupt()可获取线程的中断状态。Thread.interrupt()静态方法内部会调用当前线程的isinterrupt()方法,但是内部也会再次把状态标志位修改,所有一般都是用实例interrupt方法。对于Runnable实例化的线程,一般用Thread.currentThread().interrupt() 方法判断。
sleep():使当前线程进入阻塞状态。同时这个方法内部会监测interrupt状态,如果当前线程中断后,同时线程还睡眠时,会报异常java.lang.InterruptedException: sleep interrupted。sleep()并不会释放对象锁,只有锁代码块执行完后,其他线程才能够获取锁。
- 线程stop方法案例
import java.util.concurrent.TimeUnit;
/**
* @ClassName xu01
* @Description des
* @Author zyk
* @Date 2019/9/24
* @Version 1.0
**/
public class xu01 {
private static class UseThread extends Thread{
@Override
public void run() {
while(true) {
System.out.println("正在写入文件,写入部分...");
}
}
}
public static void main(String[] args) {
UseThread useThread=new UseThread();
useThread.start();
//main线程睡眠20
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//main线程2秒后关闭
// 1:stop() 是一个@Deprecated不推荐使用,过于野蛮停止线程(会出现线程写部分文件就挂了)
useThread.stop();
System.out.println("main 线程结束");
}
}
- 线程interrupt方法案例
import java.util.concurrent.TimeUnit;
/**
* @ClassName xu01
* @Description des
* @Author zyk
* @Date 2019/9/24
* @Version 1.0
**/
public class xu01 {
private static class UseThread extends Thread{
@Override
public void run() {
while(true) {
System.out.println("正在写入文件,写入部分...");
//判断线程状态是否,是否需要结束
// if(isInterrupted()){
//Thread.interrupted静态方法也是同样的功能,内部会获取当前线程
if(Thread.interrupted()){
System.out.println("线程状态:"+interrupted());
System.out.println("判断当前文件写完了,然后结束线程,不会导致文件是个损坏的文件");
break;
}
}
}
}
public static void main(String[] args) {
UseThread useThread=new UseThread();
useThread.start();
//main线程睡眠20
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//main线程2秒后关闭
//只是标记线程标志位为中断状态,需要在run方法中写逻辑结束线程,否则线程还是不能够结束
useThread.interrupt();
System.out.println("main 线程结束");
}
}
- 线程sleep方法案例
在线程中添加sleep睡眠逻辑,做完一件事后睡眠一段时间,再次做事情。
import java.util.concurrent.TimeUnit;
/**
* @ClassName xu01
* @Description des
* @Author zyk
* @Date 2019/9/24
* @Version 1.0
**/
public class xu01 {
private static class UseThread extends Thread{
@Override
public void run() {
while(true) {
System.out.println("正在做某件任务...");
System.out.println("结束一段任务后,线程睡眠一段时间");
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(Thread.interrupted()){
System.out.println("线程状态:"+interrupted());
System.out.println("判断当前文件写完了,然后结束线程,不会导致文件是个损坏的文件");
break;
}
}
}
}
public static void main(String[] args) {
UseThread useThread=new UseThread();
useThread.start();
//main线程睡眠20
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//main线程2秒后关闭
//只是标记线程标志位为中断状态,需要在run方法中写逻辑结束线程,否则线程还是不能够结束
useThread.interrupt();
System.out.println("main 线程结束");
}
}
注意:这样线程并不会结束,运行结果如下
正在做某件任务...
结束一段任务后,线程睡眠一段时间
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at controller.multithread.xu01$UseThread.run(xu01.java:21)
main 线程结束
正在做某件任务...
结束一段任务后,线程睡眠一段时间
正在做某件任务...
结束一段任务后,线程睡眠一段时间
这是因为 TimeUnit.MILLISECONDS.sleep(20);会抛出异常后,把当前线程中断状态又改回去了,导致线程还会继续执行。
需要修改代码:第一种方式,在sleep方法上添加try-catch,在InterruptedException异常代码块中再次调用interrupte()方法。第二种方式,把while死循环监视起来,出现InterruptedException 异常后结束线程,修改后代码如下:
import java.util.concurrent.TimeUnit;
/**
* @ClassName xu01
* @Description des
* @Author zyk
* @Date 2019/9/24
* @Version 1.0
**/
public class xu01 {
private static class UseThread extends Thread{
@Override
public void run() {
try {
while (true) {
System.out.println("正在做某件任务...");
System.out.println("结束一段任务后,线程睡眠一段时间");
try {
TimeUnit.MILLISECONDS.sleep(20);
//java.lang.InterruptedException: sleep interrupted 需要把这个异常抛出去
} catch (InterruptedException e) {
//interrupt();
throw e;
}
if (Thread.interrupted()) {
System.out.println("线程状态:" + interrupted());
System.out.println("判断当前文件写完了,然后结束线程,不会导致文件是个损坏的文件");
break;
}
}
}catch (InterruptedException e){
e.printStackTrace();
System.out.println("子线程结束");
}
}
}
public static void main(String[] args) {
UseThread useThread=new UseThread();
useThread.start();
//main线程睡眠20
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//main线程2秒后关闭
//只是标记线程标志位为中断状态,需要在run方法中写逻辑结束线程,否则线程还是不能够结束
useThread.interrupt();
System.out.println("main 线程结束");
}
}
- 线程池使用
JDK1.8不在推荐使用Executors创建线程了,推荐使用ThreadPoolExecutor,可控制最大线程数量。而Executors 最多创建线程数量是 Integer.MAX_VALUE 会导致系统OOM问题。
public static void main(String[] args) throws ExecutionException, InterruptedException {
int count=230;
//线程池1:
ExecutorService pool1=Executors.newCachedThreadPool();
ExecutorService pool2=Executors.newFixedThreadPool(5);
//线程池2:
ThreadFactory namedThreadFactory=new ThreadFactoryBuilder()
.setNameFormat("jake-pool-%d")
.build();
ExecutorService pool=new ThreadPoolExecutor(5,200,
60L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(1024),
namedThreadFactory,new ThreadPoolExecutor.AbortPolicy());
for(int i=0;i<count;i++){
pool.execute(()->{
System.out.println("========线程名称:"+Thread.currentThread().getName());
});
}
pool.shutdown();
System.out.println("shutdown");
}