创建线程的方式
创建线程一般通过继承Thread、实现Runnable接口、ExecutorService、Callable和Future等多种方式。
Thread实现
package all;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("测试Thread");
}
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
myThread1.start();
MyThread myThread2 = new MyThread();
myThread2.start();
}
}
Runnable实现
package all;
public class MyRunnable implements Runnable {
private volatile int i =5;
@Override
public void run() {
while (i > 0){
System.out.println("Runnable测试");
--i;
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
Thread thread1 = new Thread(myRunnable);
thread1.start();
}
}
Callable和FutureTask
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
public String call() throws Exception {
return "TestCallable";
}
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask = new FutureTask(new MyCallable());
futureTask.run();
if(futureTask.isDone()){
System.out.println(futureTask.get());
}
}
}
线程的生命周期
1.NEW:初始状态,线程被创建,但是还没有调用start方法
2.RUNNABLE:运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中”
3.BOLCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了 CPU 使用权,阻塞也分为几种情况
–>等待阻塞:运行的线程执行 wait 方法,jvm 会把当前线程放入到等待队列
–>同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程锁占用了,那么jvm会把当前的线程放入到锁池中
–>其他阻塞:运行的线程执行 Thread.sleep 或者 t.join 方法,或者发出了I/O请求时,JVM 会把当前线程设置为阻塞状态,当 sleep 结束、join线程终止、io处理完毕则线程恢复
4.TIME_WAITING:超时等待状态,超时以后自动返回
5.TERMINATED:终止状态,表示当前线程执行完毕
代码演示:
import java.util.concurrent.TimeUnit;
public class ThreadTest {
public static void main(String[] args) {
//TIME_WAITING
new Thread(()->{
while (true){
try {
TimeUnit.SECONDS.sleep(1000);
}catch (InterruptedException ex){
ex.fillInStackTrace();
}
}
},"测试Time_Waiting").start();
//WAITING
new Thread(()->{
while (true){
synchronized (ThreadTest.class){
try {
ThreadTest.class.wait();
}catch (InterruptedException ex){
ex.fillInStackTrace();
}
}
}
},"测试WAITING").start();
new Thread(new BlockedDemo(),"BlockedDemo01").start();
new Thread(new BlockedDemo(),"BlockedDemo02").start();
}
}
class BlockedDemo extends Thread{
public void run(){
synchronized (BlockedDemo.class){
while(true){
try {
TimeUnit. SECONDS .sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
通过idea终端输入jps查到线程进程,使用jstack 进程查看堆栈信息
终止线程(Interrupt)
其它线程通过调用当前线程的Thread.Interrupt()方法向当前线程发送一个信号,告诉它可以中断线程的执行了,至于什么时候中断,取决于当前线程自己。
判断线程是否中断可以使用Thread.currentThread().isInterrupted()来实现。
下面是一个例子:
package all;
public class ThreadTest {
private static int i;
public static void main(String[] args) throws Exception {
Thread thread = new Thread(()->{
//默认状态是false,
while(!Thread.currentThread().isInterrupted()){
i++;
}
System.out.println("Num:"+i+",isInterrupted:"+Thread.currentThread().isInterrupted());
},"测试线程");
thread.start();
Thread.sleep(1);
//发送中断标识,isInterrupted赋值true
thread.interrupt(); //可以注释掉试试效果
}
}
执行结果:
Num:7124,isInterrupted:true
Process finished with exit code 0
线程的复位
线程的中断就是通过Thread.Interrupt()方法把isTerrupted的值从false改为true,但是中断把值改为true以后什么也没有做,是不是应该恢复到原始值呢,恢复原始值就是线程的复位通过Thread.interrupted,这只是我的个人理解。
通过同一个代码对比一下:
package all;
public class ThreadTest {
public static void main(String[] args) throws Exception {
Thread thread = new Thread(()->{
while(true){
//初始值是flase
if(Thread.currentThread().isInterrupted()){
System.out.println("复位前的值:"+Thread.currentThread().isInterrupted());
Thread.interrupted();
System.out.println("复位后的值:"+Thread.currentThread().isInterrupted());
}
}
},"测试线程Thread.interrupted()");
thread.start();
Thread.sleep(1);
thread.interrupt(); //发送中断标识赋值为true
}
}
执行结果:
复位前的值:true
复位后的值:false
为什么要复位
Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号,
但不会立刻中断自己,具体什么时候中断由自己决定,让外界知道在自身中断前,他的中断状态仍然是 false,这就
是复位的原因。
线程的启动原理
从图中可以看出start方法会通过JVM创建一个线程,然后回调run方法,等于是主线程和新创建的线程一起执行。
run方法没有创建怎么线程只有一个主线程等于同步执行。