进程
进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
线程
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。
分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
Thread
是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
线程的常用操作
- getName()获取线程名字 一般使用构造方法进行设置
- currentThread() 获取当前线程
- isAlive() 判断线程是否启动
- isDaemon() 是不是后台线程 需要使用setDaemon(boolean on)
- Join() 等待该线程停止 合并线程 强制执行
- Sleep 线程休眠
- Yield() 礼让线程
Thread类
Thread是程序中的执行线程,Java 虚拟机允许应用程序并发地运行多个执行线程。
- 构造方法
- 常用方法
run() |
| |
start() |
| |
sleep() |
|
线程的实现
- 将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,开启线程。run方法相当于其他线程的main方法。
-
声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。
一个程序的运行至少会开启一个进程和两个线程:主线程、GC线程
继承实现方法一:子类继承Thread
创建线程的步骤
1 定义一个类继承Thread。
2 重写run方法。
3 创建子类对象,就是创建线程对象。
4 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。
- 自定义线程类
public class MyThread extends Thread {
//定义指定线程名称的构造方法
public MyThread(String name) {
//调用父类的String参数的构造方法,指定线程的名称
super(name);
}
/**
* 重写run方法,完成该线程执行的逻辑
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+":正在执行!"+i);
}
}
}
- 测试类
public class Demo01 {
public static void main(String[] args) {
//创建自定义线程对象
MyThread mt = new MyThread("新的线程!");
//开启新线程
mt.start();
//在主方法中执行for循环
for (int i = 0; i < 10; i++) {
System.out.println("main线程!"+i);
}
}
}
继承Thread类原理
我们为什么要继承Thread类,并调用其的start方法才能开启线程呢?
继承Thread类:因为Thread类用来描述线程,具备线程应该有功能。那为什么不直接创建Thread类的对象呢?如下代码:
Thread t1 = new Thread();
t1.start();
/*
这样做没有错,但是该start调用的是Thread类中的run方法,
而这个run方法没有做什么事情,更重要的是这个
run方法中并没有定义我们需要让线程执行的代码。
*/
创建线程的目的是什么?
是为了建立程序单独的执行路径,让多部分代码实现同时执行。也就是说线程创建并执行需要给定线程要执行的任务。
对于之前所讲的主线程,它的任务定义在main函数中。自定义线程需要执行的任务都定义在run方法中。
线程名称的获取
继承实现方法二:实现Runnable接口
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。
- 接口中的方法
- Thread类构造方法
创建线程的步骤。
1、定义类实现Runnable接口。
2、覆盖接口中的run方法。。
3、创建Thread类的对象
4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
5、调用Thread类的start方法开启线程。
自定义线程执行任务类
public class MyRunnable implements Runnable{
//定义线程要执行的run方法逻辑
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我的线程:正在执行!"+i);
}
}
}
main方法内容
public class Demo02 {
public static void main(String[] args) {
//创建线程执行目标类对象
Runnable runn = new MyRunnable();
//将Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread thread = new Thread(runn);
Thread thread2 = new Thread(runn);
//开启线程
thread.start();
thread2.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程:正在执行!"+i);
}
}
}
Runnable实现的原理
为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?
实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中。
创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。
实现Runnable的好处
- 线程和任务分离,提升线程重用性。
- 控制线程并发数量,降低服务器压力,统一管理所有线程。
- 提升系统响应的速度,省去了创建和销毁的时间,只负责执行就可以。