在学习之前我们需要对多线程有一个基本的了解,如下图:
在途中可以看出软件正在下载多个文件或者程序,这样的过程就是要用到我们的多线程,所以可以看出Java里的多线程作用非常的大,而需要学习多线程我们需要学习一些基本的概念。
1.并发和并行
- 并行:指两个或多个事件在同一时刻发生(同时执行)。
- 并发:指两个或多个事件在同一个时间段内发生(交替执行)。
2.线程与进程
-
进程:进程是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;
-
进程是应用程序的可执行单元
-
一个应用程序可以有多个进程
-
每个进程执行都会有独立的内存空间
-
-
线程:是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一条线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
- 线程是进程的可执行单元
-
一个进程可以有多条线程
- 每个线程执行都会有独立的内存空间
-
java只有单进程,然后有多线程
-
一个进程一次只能执行一条线程,所以java中只有多线程并发,没有多线程并行
-
线程的调度:
- 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间
- 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)
- Java线程的调度方式: 抢占式
学习完了在线概念我们来看一下怎么创建线程:
继承方式创建线程:
步骤:
- 创建一个子类继承Thread类
- 在子类中重写run方法,把线程需要执行的任务代码放入run方法中
- 创建子类对象,调用start()方法启动线程,执行任务
public class MyThread extends Thread {
@Override
public void run() {
// 线程需要执行的任务代码
for (int i = 0; i < 100; i++) {
System.out.println("子线程i的值是:"+i);
}
}
}
public class Test {
public static void main(String[] args) {
/*
- 创建一个子类继承Thread类
- 在子类中重写run方法,把线程需要执行的任务代码放入run方法中
- 创建子类对象,调用start()方法启动线程,执行任务
注意:
1.线程不能重复启动,只能启动一次
2.启动线程,一定要调用start()方法
*/
// 创建线程对象
MyThread mt = new MyThread();
// 启动线程,执行任务
mt.start();// 默认调用run方法
// 线程需要执行的任务代码
for (int j = 0; j < 100; j++) {
System.out.println("主线程j的值是:"+j);
}
}
}
实现方式创建线程:
-
Runnable是一个任务接口,里面有一个抽象方法run(),可以在run方法中书写线程的任务代码
-
实现步骤:
- 创建实现类实现Runnable接口
- 在实现类中,重写run方法,把线程需要执行的任务代码放入run方法中
- 创建实现类对象
- 创建Thread线程对象,并传入实现类对象
- 使用Thread线程对象调用start方法启动线程,执行任务
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程需要执行的任务代码
for (int i = 0; i < 100; i++) {
System.out.println("子线程i的值是:"+i);
}
}
}
public class Test {
public static void main(String[] args) {
/*
实现步骤:
- 创建实现类实现Runnable接口
- 在实现类中,重写run方法,把线程需要执行的任务代码放入run方法中
- 创建实现类对象
- 创建Thread线程对象,并传入实现类对象
- 使用Thread线程对象调用start方法启动线程,执行任务
*/
// 创建实现类对象
MyRunnable mr = new MyRunnable();
// 创建Thread线程对象
Thread t = new Thread(mr);
// 启动线程执行任务
t.start();
// 主线程需要执行的任务代码
for (int j = 0; j < 100; j++) {
System.out.println("主线程j的值是:"+j);
}
}
}
创建并启动多条线程
通过实现的方法:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":开始执行线程任务代码...");
// 暂停
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":结束执行线程任务代码...");
}
}
public class Test {
public static void main(String[] args) {
// 创建任务对象
MyRunnable mr = new MyRunnable();
// 创建并启动多条线程-->默认名称
new Thread(mr).start();
new Thread(mr).start();
new Thread(mr).start();
new Thread(mr).start();
new Thread(mr).start();
// 创建并启动多条线程-->指定名称
new Thread(mr,"张三1").start();
new Thread(mr,"张三2").start();
new Thread(mr,"张三3").start();
new Thread(mr,"张三4").start();
new Thread(mr,"张三5").start();
}
}
实现接口方式的好处:
1. 适合多个相同的程序代码的线程去共享同一个资源(任务)。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
同时并不只是占有这两种才可以创建多线程,还有比如:匿名内部类的方式