线程的创建
Thread类:
继承Thread类的方式创建线程
重写run方法,在run方法内想做需要在子线程中完成的事情
实例化Thread子类对象,就是创建了线程对象
调用start方法就是开启了线程
public class helloworld extends Thread {
public static void main(String[] args) {
System.out.println("====创建线程====");
helloworld helloworld = new helloworld();
System.out.println("====启动线程====");
helloworld.start();
}
public void run(){
System.out.println("hello:"+currentThread().getName());
}
}
Runnable接口
有一个类实现Runnable接口,重写run方法,整个run方法就是线程的执行体。
创建Runnable的类,传到Thread类的构造函数里面去创建一个Thread类的对象,这个Thread对象才是真正的线程对象
public class helloworld implements Runnable {
public static void main(String[] args) {
System.out.println("====实现runnable接口====");
helloworld helloworld = new helloworld();
System.out.println("====创建线程====");
Thread thread = new Thread(helloworld);
System.out.println("====启动线程====");
thread.start();
}
public void run(){
System.out.println("hello");
}
}
Callable接口
可以有返回值携带回来
创建一个Callable的实现类,实现call方法,call方法里面装的就是线程的执行逻辑,且该call方法有返回值
拿到Callable的实现类之后,FutureTask类来包装这个实现类。
这个FutureTask对象封装了这个Callable实现类的call方法的返回值
然后使用FutureTask对象作为参数,传到Thread类的构造函数里去,创建,启动一个线程,调用start方法让他去跑,跑完了以后可以用FutureTask的get方法获得子线程结束后的返回值
public class helloworld {
public static void main(String[] args) {
//FutureTask对象
//Lambda表达式
FutureTask task = new FutureTask(()->{
int count = 0;
for (int i=0;i<=100;i++){
count += i;
}
return count;
});
//创建线程
Thread thread = new Thread(task);
//启动线程
thread.start();
try {
//获取线程返回值
System.out.println("1+2+3+...+100 ="+task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public void run(){
System.out.println("hello");
}
}
Callable接口使用场景
比如查询商品列表
对方没有批量接口,就用这个方法多线程分别查询每个商品信息,每个线程需要返回商品的信息,再组装,就是一口气并发出去接收回来,而不是一次次请求出去
线程池创建线程
/
线程的生命周期
新建 :new关键字创建线程对象的状态。
就绪:通过线程对象的start方法启动线程时对应的状态,此时线程不一定马上进入运行状态,线程的运行由操作系统的调度程序控制。当前CPU有空闲就很有可能直接执行,如果CPU没有空闲,这个线程没有能得到CPU的时间片,就不能立即执行。
运行:得到了CPU的执行权,线程正在执行需要执行的代码。
阻塞:线程被挂起,通常原因是在等待一个锁,没办法执行线程体。
等待:分为有限期等待和无限期等待。无限期等待需要被唤醒。
结束:线程结束,把相关资源释放掉。
线程阻塞:
1.线程在等待一个锁对象,比如代码里面加了一个synchronized方法块,锁被其他线程占有了,当前线程获取不到,就进行到了阻塞状态。或者发生了wait操作就进入等待状态了。
2.对阻塞的线程调用thread.interrupt(),也无法改变其阻塞状态,因为thread.interrupt()只是设置线程中断状态,不能唤醒处于阻塞状态的线程。
3.ReentrankLock.lock()操作后进入的是waiting状态,其内部调用的是LockSupport.park()方法
线程无限期等待
处于这种状态的线程不会被CPU分配执行时间,他们要等待被其他线程唤醒
没有设置timeout参数的Object.wait()
没有设置timeout参数的Thread.join()
LockSupport.park()
线程的有限期等待
处于这种状态的线程也不会被CPU分配执行时间,不过不需要等待被其他线程显示的唤醒,在一定时间后他们会由系统自动唤醒
Thread.sleep()方法
设置了timeout的Object.wait()方法
设置了timeout的Thread.join()方法
LockSupport.parkNanos()方法
LockSupport.parkUntil()方法
线程阻塞和线程等待的区别
阻塞是等待着获取一个锁对象的释放,进入阻塞是被动的,离开阻塞状态是因为其他线程释放了锁对象,自己获取到了执行权,就不阻塞了。(不受开发控制的,其他线程竞争到资源,自己就被迫被阻塞了)
等待状态是在等待一段时间,或者唤醒动作的发生,进入等待状态是主动的。是自己进入的。
线程结束
run(),call()方法正常执行完,就是正常结束线程
线程抛出一个未捕获的Exception或者Error,也会执行结束
或者开发人员调用了stop()方法结束线程
网友评论