文章目录
进程与线程
进程:是指一个内存中运行的应用程序。
比如鼠标点击应用程序“记事本”,“记事本”程序进入到内存中,占用了一些内存执行的这个程序就是进程。
线程:线程则是进程的一个执行路径;一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
比如运行360安全卫士,该程序就会进入到内存中,即启动了进程;当我们运行安全卫士的某个功能,比如木马查杀,则该进程就会开启一个执行路径,进行电脑上的木马查杀工作;同时当我们运行电脑清理这个功能时,进程又会开启另一个执行路径,进行电脑清理工作,运行系统修复、优化加速功能同样如此,这些开启的执行路径,即是线程,也就是说一个进程中会存在多个线程,多个线程可以并发处理。
线程调程
1、分时调度
是指让所有的线程轮流获得cpu的使用权,并且平均分配每个线程占用的CPU的时间片。
2、抢占式调度
是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程会一直运行,直至它不得不放弃CPU。
Java虚拟机采用的是抢占式调度。
主线程的定义
当Java程序启动时,一个线程立刻运行,则该线程通常叫做程序的主线程(main thread)。
/**
* @author zhuhuix
*/
public class MainThread {
//程序启动时main方法立刻执行,即启动主线程
public static void main(String[] args) {
//主线程启动后通过循环依次打印1-100
for (int i=1;i<=100;i++){
System.out.println("主线程打印:"+i);
}
//主线程完成以上打印后再循环依次打印A-Z
for (char c='A';c<='Z';c++){
System.out.println("主线程打印:"+c);
}
}
}
主线程运行输出的打印结果如下:
创建多线程的第一种方式:创建Thread类的子类
- 创建一个Thread类的子类
- 在Thread类的子类中重写run方法:设置线程任务
- 创建Thread类的子类对象
- 调用Thread类中的成员方法start方法,开启新的线程:即执行run方法
/**
* 通过继承Thread类创建多线程程序
*
* @author zhuhuix
*/
public class Thread01 extends Thread {
//通过重写run方法设置线程任务
@Override
public void run() {
for (char c='A';c<='Z';c++){
System.out.println("子线程打印:"+c);
}
}
}
/**
* 多线程打印输出
* @author zhuhuix
*/
public class MainThread {
public static void main(String[] args) {
//创建继承于Thread类的子类对象
Thread01 thread01 = new Thread01();
//调用Thread类的成员方法start启线线程任务
thread01.start();
//主线程启动后通过循环依次打印1-100
for (int i = 1; i <= 100; i++) {
System.out.println("主线程打印:" + i);
}
}
}
执行结果如下图:(主线程与子线程通过抢占CPU资源完成各自地打印输出任务,抢占CPU资源具有随机性)
多线程的内存图
多线程执行时,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈,这样也就给CPU开了多个执行路径,可以进行并发执行。
Thread的常用方法
获取线程名称与设置线程名称 :
/**
* 通过继承Thread类创建多线程程序
*
* @author zhuhuix
*/
public class Thread01 extends Thread {
//通过重写run方法设置线程任务
@Override
public void run() {
//获取当前子线程名称
String currentThreadName=Thread.currentThread().getName();
for (char c='A';c<='Z';c++){
System.out.println(currentThreadName+":"+c);
}
}
}
/**
* @author zhuhuix
*/
public class MainThread {
public static void main(String[] args) {
//创建继承于Thread类的子类对象
Thread01 thread01 = new Thread01();
//调用Thread类的成员方法start启线线程任务
thread01.start();
//创建继承于Thread类的子类对象
Thread01 thread02 = new Thread01();
//通过setName设置线程名称
thread02.setName("子线程2");
//调用Thread类的成员方法start启线线程任务
thread02.start();
//主线程启动后通过循环依次打印1-100
for (int i = 1; i <= 100; i++) {
System.out.println("主线程打印:" + i);
}
}
}
执行效果如下:
Sleep方法:
对正在执行的线程以指定的毫秒数暂停执行
/**
* 通过继承Thread类创建多线程程序
*
* @author zhuhuix
*/
public class Thread01 extends Thread {
//通过重写run方法设置线程任务
@Override
public void run() {
//打印当前子线程名称
String currentThreadName=Thread.currentThread().getName();
for (char c='A';c<='Z';c++){
System.out.println(currentThreadName+":"+c);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 使用sleep方法
* @author zhuhuix
*/
public class ThreadSleep {
//程序启动时main方法立刻执行,即启动主线程
public static void main(String[] args) throws InterruptedException {
//创建继承于Thread类的子类对象
Thread01 thread01 = new Thread01();
//调用Thread类的成员方法start启线线程任务
thread01.start();
//主线程启动后通过循环依次打印1-100
for (int i = 1; i <= 100; i++) {
System.out.println("主线程打印:" + i);
Thread.sleep(1000);
}
}
}
执行效果如下:
创建多线程的第二种方式:声明实现Runnable接口的类
- 创建一个实现Runnable接口的实现类
- 在该实现类中重写run方法:设置线程任务
- 创建一个实现类的对象
- 创建Thread类对象,构造方法中传递这个实现类
- 调用Thread类对象的start方法,开启新的线程。
/**
* 通过创建实现Runnable接口的类实现多线程程序
*
* @author zhuhuix
*/
public class Thread02 implements Runnable {
@Override
public void run() {
for (char c = 'A'; c <= 'Z'; c++) {
System.out.println("子线程打印:" + ":" + c);
}
}
}
public class ThreadMethod {
public static void main(String[] args) {
//创建实现了Runnable接口的实现类的对象
Thread02 thread02 = new Thread02();
//创建一个Thread类的对象,构造函数中传递实现了Runnable接口的实现类的对象
//调用Thread类的对象的方法start,启动多线程任务
new Thread(thread02).start();
//主线程启动后通过循环依次打印1-100
for (int i = 1; i <= 100; i++) {
System.out.println("主线程打印:" + i);
}
}
}
执行效果如下:
实现Runnable接口创建多线程程序的好处:
- 由于java的类只能继承一个类,即如果一个类继承了Thread类就不能继承其他的类;而实现Runnable的接口的实现类,还可以继承其他类。
- 实现Runnable接口创建多线程,可以利用接口式方式编程的优点,把设置线程任务和开启新线程进行分离与解藕。
结论:一般我们创建多线程程序,尽量采用实现Runnable接口的创建方式。