线程的基本认识
1.线程的基本介绍
线程是操作系统能够进行运算调度的最小单位。它包含在进程之后,是进程中实际的运作单位
为什么会有线程
在多核cpu中利用多线程可以实现真正意义上的并行执行
在一个应用进程中,会存在多个同时执行的任务,如果其中一个任务呗阻塞,将会引起不依赖该任务的任务也被阻塞,通过对不同任务创建不同的线程去处理,可以提升程序处理的实时性
线程可以认为是轻量级的进程,所以线程的创建,销毁比进程快
为什么要用多线程
异步执行
利用多cpu资源实现真正意义上的并行执行
线程应用场景
使用多线程实现文件下载
后台任务,如定时向大量(100W)以上的用户发送邮件
异步处理:记录日志
多步骤的任务处理,可以根据步骤特征选用不同个数和特征的线程,协助处理,多个任务分割,由一个主线程分割给多个线程完成
总结:
多线程的本质:合理的利用多核心cpu资源来实现线程的并行处理,来实现同一个进程内多个任务的并行执行,同时基于线程本身的异步执行特性,提升任务处理的效率
2.在java中使用多线程的方式
继承Thread类
public class ThreadTest extends Thread{
@Override
public void run() {
//打印当前线程
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
new ThreadTest().start();
}
}
执行结果:
Thread-0
实现Runnable接口
public class RunnableTest implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
RunnableTest runnableTest = new RunnableTest();
//不能直接通过runnableTest.start方法,因为是接口
Thread thread = new Thread(runnableTest);
thread.start();
}
}
运行结果
Thread-0
实现Callable接口
public class CallableTest implements Callable {
public String call() throws Exception {
return "success";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//callable需要使用线程池的方式传入参数
ExecutorService service = Executors.newFixedThreadPool(1);
Future future = service.submit(new CallableTest());
System.out.println(future.get());
}
}
执行结果
success
3.java线程的声明周期线程从创建到销毁,一共经历6个状态
NEW:初始状态,线程被构建,但是还没有调用start方法
RUNNABLED:运行状态,JAVA线程把操作系统中的继续和运行两种状态统称为运行中
BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了CPU使用权,阻塞也分几种情况
WAITING:等待状态
TIME_WAITING:超时等待状态,超时以后自动返回
TERMINATED:终止状态,表示当前线程执行完毕
演示不同的方法对线程声明周期的影响,实例
public class TestDemo {
public static void main(String[] args) {
// TIME_WAITING
new Thread(()->{
while (true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
},"Time_Waiting_Demo").start();
// WAITING
new Thread(()->{
while (true){
synchronized (TestDemo.class){
try {
TestDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Waiting_Demo").start();
//BLOCKED
new Thread(new BlockedDemo(),"Blocked_Demo_01").start();
new Thread(new BlockedDemo(),"Blocked_Demo_02").start();
}
static class BlockedDemo extends Thread{
public void run() {
synchronized (BlockedDemo.class){
while (true){ //死循环,让获得锁的线程不释放
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
运行中的线程日志如何查看
在命令行中执行如下命令查看
jps查看线程日志栈,找到TestDemo对应的编号,复制
执行jstack + 7192(进程号)查看详细日志
名称为Blocked_Demo_02的线程为阻塞状态,因为名称为Blocked_Demo_01的线程拿到了锁未释放
名称为Waiting_Demo的线程调用wait方法,让线程进入waiting状态
名称为Time_Waiting_Demo的线程调用sleep方法,让线程进入TIMED_WAITING状态