一、进程和线程的关系
1.1 进程
一个在内存运行的应用程序。每个进程都有自己独立的一块内存空间,用于加载执行指令等。
例如:在Windows中,执行一个exe就是一个进程;在Java中,执行
java -jar xxxx.jar
,就是开启一个JVM进程。
1.2 线程
线程是进程中的一个执行单元,一个进程至少有一个线程,可以运行多个线程。在Java中,执行程序的入口
main()
,会开启一个主线程,然后在主线程中,可以开启多个线程。JVM内存结构中,
方法栈
、本地方法栈
和程序计数器
是线程私有的,堆
和方法区
是线程共享的。
二、Java线程创建(未使用线程池)
使用
Thread类
:Thread thread = new Thread(){ @Override public void run() { log.debug("thread running..."); } }; log.debug("main start other thread..."); thread.setName("create"); thread.start(); log.debug("main end...");
使用
Thread类
和Runnable接口
Runnable runnable = new Runnable() { @Override public void run() { log.debug("runnable create thread..."); } }; Thread thread = new Thread(runnable,"runnable"); log.debug("main start other thread..."); thread.start(); log.debug("main end...");
使用
Thread类
和FutureTask接口
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { log.debug("future task do something..."); return "future task..."; } }); Thread futureTaskThread = new Thread(futureTask, "futureTask"); log.debug("future task thread start..."); futureTaskThread.start(); log.debug("{}", futureTask.get()); log.debug("future task thread end...");
注
:FutureTask接口是一个带返回值线程接口,当调用futureTask.get()
方法时,主线程会阻塞,等待call()
方法执行结束,并返回数据。
三、Java线程常见方法
方法名 描述 start()
用于开启一个线程 run()
执行线程的业务逻辑,当一个线程开启后,会执行 run()方法
里的逻辑。sleep()
让当前线程睡眠,进入阻塞状态;当睡眠时间结束,则等待获取CPU执行时间。 yield()
当前线程放弃CPU资源,从 运行状态
进入就绪状态,
和其他线程共同竞争CPU执行权。join()
等待线程运行结束 interrupt()
将线程中断标志 interrupted
设置true
,当线程处于sleep
、wait
或join
阻塞状态,则会抛出InterruptedException
异常,并将interrupted
状态设置为false
。stop()
暴力停止线程;不推荐使用因为会将线程直接停止,如果有未执行完的程序,也会被直接停止。例如:线程A加了锁,直接停止,未释放锁,如果线程B正等待该锁释放,则线程B会死锁;停止线程推荐使用 两阶段终止模式
。
两阶段终止模式
:使用interrupt()
打断线程,线程自己通过interrupted
判断是否打断,如果被打断,则自己判断何时执行结束(例如:释放锁后线程在执行结束)。
四、主线程和守护线程
- 主线程:主要运行main方法。
- 守护线程:用于服务其它线程(主线程和主线程中创建的线程),当主线程执行结束,此时JVM退出,无论守护线程执行到哪,都会强制关闭,因为此时程序已经执行完毕。
- Java最常见守护线程是:垃圾回收哦器线程。
五、Java线程状态
5.1 操作系统层面划分线程状态(五种)
初始状态
当定义了一个线程,此时线程处于初始状态,未与操作系统产生关联。
可运行状态
当线程被创建后,等待获得CPU的执行时间。
运行状态
线程获得CPU的执行时间;当CPU执行时间片结束,线程还未执行结束,则会由【运行状态】切换到【可运行状态】,等待获取下次的执行时间片;如果线程执行结束,则切换到【终止状态】。
阻塞状态
当【运行状态】的线程调用
BIO
等阻塞API时,此时线程无需CPU参与,会让出CPU执行时间片,进入【阻塞状态】;当阻塞API执行结束,线程会从【阻塞状态】切换到【可运行状态】,等待下次执行时间片。终止状态
线程执行结束,进入【终止状态】;此时,线程的生命周期也结束。