# 多线程-初识
🐴
# 前言
我们在讨论线程之前不得不提进程。进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。(例如电脑上打开一个微信就是启动了一个进程,打开浏览器也是启动了一个进程)
它们得区别如下:
- 进程是操作系统分配资源的最小单位,而线程是程序执行的最小单位
- 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
- 调度和切换:线程上下文切换比进程上下文切换要快得多
# 生命周期
线程得生命周期分为五个阶段
新建状态 New
当现在对象创建后,就进入了新建状态就绪状态 Runnable
当调用线程对象得start()
方法后,线程就进入就绪状态。此时线程并没有执行,只是做好了准备,等待CPU
调度执行运行状态 Running
当CPU
调度该线程,执行run()
方法时,线程进入运行状态阻塞状态 Blocked
正在运行得线程,由于某种原因(sleep
(睡眠)、suspend
(挂起))暂时停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。终止状态 Terminated
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
# Thread的常用方法
Thread
类的常用方法
方法 | 描述 |
---|---|
public void start() | 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
public void run() | 如果该线程是使用独立的Runnable 运行对象构造的,则调用该Runnable 对象的run 方法;否则,该方法不执行任何操作并返回。 |
public final void setName(String name) | 改变线程名称,使之与参数name 相同。 |
public final void setPriority(int priority) | 更改线程的优先级。 |
public final void setDaemon(boolean on) | 将该线程标记为守护线程或用户线程。 |
public final void join(long millisec) | 等待该线程终止的时间最长,millis 为毫秒。 |
public void interrupt() | 中断线程。 |
public final boolean isAlive() | 测试线程是否处于活动状态。 |
public static void yield() | 暂停当前正在执行的线程对象,并执行其他线程。 |
public static void sleep(long millisec) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
public static boolean holdsLock(Object x) | 当且仅当当前线程在指定的对象上保持监视器锁时,才返回true 。 |
public static Thread currentThread() | 返回对当前正在执行的线程对象的引用。 |
public static void dumpStack() | 将当前线程的堆栈跟踪打印至标准错误流。 |
# 创建
在java
中创建线程有三种方法:
- 继承
Thread
类 - 实现
Runnable
接口 - 通过
Callable
和Future
创建线程。
# Thread类
class ThreadTest extends Thread{
private String name;
ThreadTest(String name){
this.name = name;
}
public void run(){ // 重写run方法
try{
for(int i = 0; i < 3; i++){
Thread.sleep(100); //休眠
System.out.println(name + " " + i);
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
ThreadTest th1 = new ThreadTest("小明");
ThreadTest th2 = new ThreadTest("小牛");
th1.start();
th2.start();
}
// 打印结果如下:
// 小明开始执行******
// 小牛开始执行******
// 小牛 0
// 小明 0
// 小牛 1
// 小明 1
// 小牛 2
// 小明 2
# 实现Runnable接口
通过实现Runnable
接口方法来创建线程
//ThreadTest 类实现 Runbale
class ThreadTest implements Runnable{
private String name;
ThreadTest(String name){
this.name = name;
}
public void run(){ // 重写run方法
try{
for(int i = 0; i < 3; i++){
Thread.sleep(100); //休眠
System.out.println(name + " " + i);
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
public void start(){
System.out.println(name + "开始执行******");
new Thread(this,name).start();
}
}
public static void main(String[] args){
ThreadTest th1 = new ThreadTest("小明");
ThreadTest th2 = new ThreadTest("小牛");
th1.start();
th2.start();
}
// 打印结果如下:
// 小明开始执行******
// 小牛开始执行******
// 小牛 0
// 小明 0
// 小牛 1
// 小明 1
// 小牛 2
// 小明 2
# 通过Callable和Future实现
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test implements Callable<Integer> {
public static void main(String[] args){
Test threadPool = new Test();
FutureTask<Integer> future = new FutureTask<>(threadPool);
new Thread(future,"Callable").start();
try{
System.out.println("子线程的返回值:"+future.get());
}catch (InterruptedException e){
e.printStackTrace();
} catch (ExecutionException e){
e.printStackTrace();
}
}
public Integer call(){
int i = 0;
for(;i<3;i++){
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " " +i);
}catch (InterruptedException e){
e.printStackTrace();
}
}
return i;
}
}
Callable
接口实际上是属于Executor
框架中的功能类,Callable
接口与Runnable
接口的功能类似,但提供了比Runnable
更加强大的功能。
Callable
可以在任务结束的时候提供一个返回值,Runnable
无法提供这个功能Callable
的call方法分可以抛出异常,而Runnable
的run
方法不能抛出异常。
参考文献
← Java-Iterator IO-初识 →