一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
这种方法运用了模板策略:
定义一个算法流程的骨架,把一些可变节点延迟到具体的子类中去执行, 把逻辑实例和线程分开,每个线程共享同一个逻辑,是一种有效减少程序中类的数量的开发模式
//若不重写run方法或传递runnable对象,则不会运行逻辑
Thread()
//Allocates a new Thread object.
Thread(String name)
//Allocates a new Thread object.指定线程名,默认线程名‘Thread-计数’
Thread(Runnable target)
//Allocates a new Thread object.传递Runnable接口对象
Thread(Runnable target, String name)
//Allocates a new Thread object.指定线程名,默认线程名‘Thread-计数’
//线程组是为了更好的统一对线程管理,比如同时关闭组内所有线程
Thread(ThreadGroup group, Runnable target)
//Allocates a new Thread object.指定线程组,默认线程组为父线程的组
Thread(ThreadGroup group, Runnable target, String name)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group.
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group, and has the specified stack size.
//stacksize是指线程占用的栈深(递归溢出的大小),栈深越大,栈内线程可用数越少
//受操作系统影响,有些平台上未必有用
Thread(ThreadGroup group, String name)
//Allocates a new Thread object.
void setDaemon(boolean on)
//Marks this thread as either a daemon thread or a user thread.
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程),守护线程会伴随创建线程结束而结束。这个特点使用妥当可以用来结束和释放线程,不妥当会出现线程莫名中断或退出
主线程进入阻塞状态,让“主线程”等待“子线程”结束之后才能继续运行。
注意 是调用join()方法的当前线程进入阻塞,而不是调用的线程对象进入阻塞
// 主线程
public class Father extends Thread {
public void run() {
Son s = new Son();
s.start();
s.join();
...
}
}
// 子线程
public class Son extends Thread {
public void run() {
...
}
}
那么不能直接把一个线程搞挂掉, 但有时候又有必要让一个线程死掉, 或者让它结束某种等待的状态 该怎么办呢?一个比较优雅而安全的做法是:使用等待/通知机制或者给那个线程一个中断信号, 让它自己决定该怎么办。
注意事项:Thread.join(),中断信息发送的不是给Thread,而是执行Thread.join()的线程
线程结束不推荐stop()方法,并且该方法已明确过时。
如何优雅的结束线程
1. 设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出
class Demo {
private class ThreadSafe extends Thread {
@Override
public void run() {
while (exit){
//do something
}
}
}
private void shutDown(){
exit = false;
}
}
2. 捕获异常+中断状态标志判断
public class ThreadSafe extends Thread {
public void run() {
while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
try{
Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出
}catch(InterruptedException e){
e.printStackTrace();
break;//捕获到异常之后,执行break跳出循环。
}
}
}
}
2. 守护线程强制中断退出
因为有可能程序在中间阻塞,无法执行首位置的判断语句,因此需要一个强制退出的方案
public class ThreadService {
private Thread execuateThread;
private boolean isFinished;
private Long currentTimeMillis;
public void excute(Thread thread){
execuateThread = new Thread(){
@Override
public void run() {
isFinished = false;
thread.setDaemon(true);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
System.out.println("线程超时被打断");
}
isFinished = true;
System.out.println("线程执行完成");;
}
};
execuateThread.start();
}
//等待mill毫秒后若线程还在运行则将其中断
public void stop(long mill){
currentTimeMillis = System.currentTimeMillis();
while (!isFinished){
if(System.currentTimeMillis()-currentTimeMillis>mill){
execuateThread.interrupt();
break;
}
}
}
}