进程与线程
- 概述
进程
一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。
线程
进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
线程类 Thread
-
概述
1.Thread类用于创建新的线程。该类的对象调用 start() 方法可创建一个新线程,并由JVM调用该对象的 run() 方法。2.当需要创建新的线程时,可以声明一个类继承Thread类。这个子类需要重写Thread类的run方法,通过创建子类对象调用继承Thread类的 start() 方法启动新线程并由JVM调用run()方法(run()方法用于封装被线程执行的代码)。或者声明一个类实现 Runnable 接口,将该类对象作为参数调用Thread的带参构造。
-
构造方法
构造方法 描述 Thread() 创建一个 Thread对象 Thread(String name) 创建一个 Thread对象,并命名该线程 Thread(Runnable target) 创建一个 Thread对象,执行一个目标资源 Thread(Runnable target, String name) 创建一个 Thread对象,执行一个目标资源+线程命名 -
常用方法
常用方法 描述 void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法 static Thread currentThread() 返回对当前正在执行的线程对象的引用 static void sleep(long millis) 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性 void join() 等待这个线程死亡 void setDaemon(boolean on) 此线程设为守护线程,当程序只有守护线程时JVM退出 void setName(String name) 设置此线程名称 String getName() 返回此线程名称 void setPriority(int newPriority) 更改此线程的优先级 int getPriority() 返回此线程的优先级
实现多线程的两种方式
-
1.继承 Thread 类重写run()实现多线程
//线程类 class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(i); //线程休眠1秒 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } //测试类 public class Demo { public static void main(String[] args) throws InterruptedException { System.out.println("开始"); MyThread mt1 = new MyThread();//创建线程类 MyThread mt2 = new MyThread(); //调用start方法开启线程 mt1.start(); mt2.start(); System.out.println("结束"); } } ---*--- 输出结果: 开始 结束 0 0 1 1 2 2 3 3 4 4
结果可以看出,当线程类(MyTread)对象调用了start()方法之后创建了新的线程,并由JVM调用了该类的run()方法。同时main线程并没有停止而是继续往下执行。
-
2.实现 Runnable 接口重写run()实现多线程
//线程类 class MyThread implements Runnable { //0~99,间隔1秒 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } //测试类 public class newThread extends Thread { public static void main(String[] args) { // MyThread mt = new MyThread(); //创建线程对象,并设置线程名 Thread th1 = new Thread(mt,"飞机"); Thread th2 = new Thread(mt,"汽车"); //启动线程 th1.start(); th2.start(); } } ---*--- 输出结果: 飞机:0 汽车:0 飞机:1 汽车:1 汽车:2 飞机:2 ......
通过这种方式创建的线程的好处是:
1.实现接口,不占用继承功能。
2.适合多个线程执行同一个资源的情况,把线程和程序的代码、数据分离。
常用方法
-
设置和获取线程名称
//线程类 class MyThread extends Thread { @Override public void run() { System.out.Println("新线程开启了"); } } //测试类 public class newThread extends Thread { public static void main(String[] args) { MyThread mt1 = new MyThread(); //获取默认线程名 String name = mt1.getName(); System.out.println("线程默认名称是:"+name); //设置线程名,并获取 mt1.setName("读数线程-01"); name = mt1.getName(); System.out.println("修改后线程名称是:"+name); //获取当先线程名称 String nowThread = Thread.currentThread().getName(); System.out.println("当前线程名称是:"+nowThread); } } ---*--- 输出结果: 线程默认名称是:Thread-0 修改后线程名称是:读数线程-01 当前线程名称是:main
使用Thread类中的getName()和setName()方法获取和设置线程名称。还可以通过 Thread.currentThread() 方法获取当先线程对象的引用。
-
继承Thread 类通过构造方法设置线程名称
//线程类 class MyThread extends Thread { MyThread(){} MyThread(String name){ //创建带参构造并将参数传递给父类带参构造。 super(name); } @Override public void run() { System.out.println("开启了新的线程"); } } //测试类 public class newThread extends Thread { public static void main(String[] args) { MyThread mt1 = new MyThread("测试线程"); //获取线程名称 String name = mt1.getName(); System.out.println(name); } } ---*--- 输出结果: 测试线程
虽然Thread类有带参构造方法Thread(String name),可以直接设置线程名称。但是我们的线程类没有,所以需要在线程类中创建一个带参构造并将参数传给父类的带参构造实现创建对象时直接设置线程名称。
-
线程优先级
//线程类 class MyThread extends Thread { MyThread(){} MyThread(String name){ super(name); } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+"-"+i); } } } //测试类 public class newThread extends Thread { public static void main(String[] args) { MyThread mt1 = new MyThread("火箭"); MyThread mt2 = new MyThread("飞机"); MyThread mt3 = new MyThread("高铁"); //获取线程优先级 System.out.println("默认线程优先级:"+mt1.getPriority()); //5 System.out.println("默认线程优先级:"+mt2.getPriority()); //5 System.out.println("默认线程优先级:"+mt3.getPriority()); //5 //线程优先级范围 System.out.println("最大线程优先级:"+Thread.MAX_PRIORITY); //最大10 System.out.println("最小线程优先级:"+Thread.MIN_PRIORITY); //最小1 System.out.println("默认线程优先级:"+Thread.NORM_PRIORITY); //默认5 //设置线程优先级 mt1.setPriority(10); mt2.setPriority(5); mt3.setPriority(1); //执行线程 mt1.start(); mt2.start(); mt3.start(); } } ---*--- 默认线程优先级:5 默认线程优先级:5 默认线程优先级:5 最大线程优先级:10 最小线程优先级:1 默认线程优先级:5 线程优先级高获得cup时间片的概率越大,
- 线程的两种调度模型
1.分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
2.抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个, 优先级越高的线程获得cup时间片的概率越大,获取的CPU时间片相对多一些。
- 线程的两种调度模型
线程控制
-
static void sleep(long milis) 线程休眠
//测试类 public class newThread extends Thread { public static void main(String[] args) throws InterruptedException { System.out.println("开始"); Thread.sleep(3000); System.out.println("结束"); } } ---*--- 输出结果: 开始 //这里停止了3秒 结束
当线程执行到Tread.sleep()方法时,该线程将休眠给定的毫秒值。
-
void join() 等待这个线程死亡
//线程类 class Test extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(i); //休眠1s try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } //测试类 public class Demo { public static void main(String[] args) throws InterruptedException { System.out.println("开始"); Test test1 = new Test(); Test test2 = new Test(); //开启新线程 test1.start(); test2.start(); //等待这个线程死亡在往下执行 test1.join(); System.out.println("结束"); } } ---*--- 输出结果: 开始 0 0 1 1 2 2 3 3 4 4 结束
当执行到 tset1.join() 方法之后:
main线程等待该线程死亡才继续往下执行,但不影响已经开启的其他线程。 -
void setDaemon(boolean on) 设为守护线程,当只有守护线程时,JVM退出
//线程类 class Test extends Thread { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } //测试类 public class Demo { public static void main(String[] args) throws InterruptedException { //设置main线程名称 Thread.currentThread().setName("主"); //创建线程类 Test t1 = new Test(); //设置t1线程名 t1.setName("守护一"); //将t1设为守护线程 t1.setDaemon(true); //开启t1 t1.start(); for (int i = 0; i <3; i++) { System.out.println(Thread.currentThread().getName()+":"+i); Thread.sleep(1000); } } } ---*--- 输出结果: 主:0 守护一:0 主:1 守护一:1 主:2 守护一:2 Process finished with exit code 0
从结果可以看出,当主线程结束之后就只剩下守护线程。当程序只有守护线程的时候JVM将退出。
注意:守护线程必须在启动前设置。
线程生命周期
![](https://img-blog.csdnimg.cn/20210520215544228.png)