线程创建方式和常用方法小结
线程创建方式
1.继承Thread类,重写run()方法
class Mythread extends Thread{
@Override
public void run() {
System.out.println("使用继承Thread创建线程");
}
}
public class TestDemo12 {
public static void main(String[] args) {
Thread thread=new Mythread();
thread.start();
}}
2.实现Runnable接口,重写run()方法
class Mythread implements Runnable{
@Override
public void run() {
System.out.println("使用实现Runnable接口创建线程");
}
}
public class TestDemo12 {
public static void main(String[] args) {
Thread thread=new Thread(new Mythread());
thread.start();
}
}
3.实现callable接口,重写call()方法,相比于上面两种创建方式,call()方法会抛出异常并且有返回值,可以视情况选择
class Mythread implements Callable {
@Override
public Object call() throws Exception {
System.out.println("使用callable接口创建线程");
return null;
}
}
public class TestDemo12 {
public static void main(String[] args) {
Thread thread=new Thread(new FutureTask(new Mythread()));
thread.start();
}
4.使用匿名内部类创建,重写run()方法,这是比较常用的一种方式
new Thread(){
@Override
public void run() {
System.out.println("使用匿名内部类创建线程");
}
}.start();
还有一种启动方式
Thread thread=new Thread(){
@Override
public void run() {
System.out.println("不同的启动方式");
}
};
thread.start();
常用方法:
在了解常用方法之前我们需要先了解一个线程有哪些状态以及他们之间是如何转换的
NEW:新建状态
用new创建的线程处于新建状态,此时和其他的java对象一样,仅仅是在堆中分配了内存
Runable状态:就绪状态
线程调用start()方法之后,线程处于就绪状态,等待获取cpu的使用权
Running状态:运行状态
就绪的线程获得了cpu等资源,处于正在运行的状态
Blocked状态:阻塞状态
阻塞状态是指线程因为某些原因(比如:运行到某一行代码时发现缺少需要的资源或者锁),暂时停止运行,就会处于阻塞状态
Waiting状态:等待状态
当线程处于该状态,如果某个线程中的对象调用了wait()方法,JVM就会将线程放入到等待池
Timed_waiting状态:超时等待
sleep() join()方法会使线程处于休眠状态
Terminated:终止状态
当线程执行到run()方法结尾时,就进入该状态,表示线程的生命周期结束
我们再以一张图来描述线程之间的状态转换
根据这张图我们来看常用的方法
start()方法:启动线程
strat启动一个新线程,必须首先调用才能创建子线,并且不能重复使用
这里简单看下源码
if (threadStatus != 0)//判断当前线程状态是否是已经启动
throw new IllegalThreadStateException();
group.add(this);//如果没有启动将该线程放入等待池
boolean started = false;
try {
start0();//调用start0()本地方法去让操作系统去让线程执行
started = true;
}
run()方法:子线程业务逻辑
该线程所需要实现的任务,调用run()方法不会启动线程!!
yiled()方法:线程让步
该方法时当前线程让步一次cpu使用权,但是调用这个方法的线程并不一定会进入阻塞状态,它仅仅是告诉操作系统你可以拿走我当前的cpu使用权,但是如果此时系统资源足够就操作系统就会忽略这次让步,如果系统繁忙需要这一次cpu时间片,调用这个方法的线程才会进入阻塞,但是这个方法并不会释放它当前得到的锁,只是让步一次cpu使用权。
join()方法:
调用这个方法会暂停当前线程执行,等待子线程执行,jion方法时将并行执行的线程合并成串行执行,一定要注意是谁暂停了执行!!
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"主线程开始执行");
Thread thread=new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"子线程开始执行");
System.out.println(Thread.currentThread().getName()+"子线程执行结束");
}
};
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"主线程执行结束" );
}
从执行结果可以看出:子线程调用了join()方法,所以主线程暂停执行,执行完子线程后,主线程继续执行。
interrupt()方法:中断线程
用来处理处于阻塞状态的线程,这个方法并不是用来中断当前线程的运行的,而是用来中断当前的阻塞状态
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"主线程开始执行");
Thread thread=new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"子线程开始执行");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"子线程执行结束");
}
};
thread.start();
thread.interrupt();
System.out.println(Thread.currentThread().getName()+"主线程执行结束" );
}
可以看到因为sleep而进入阻塞状态的线程因为调用了interrupt方法而抛出了中断异常,并不是中断正在运行的线程,只是将当前中断标志位设置为true