多线程
1.并发和并行
- 并发:指两个或多个事件在同一个时间段内发生
- 并行:指两个或多个事件在同一个时刻发生(同时发生)
2.线程与进程的概念
- 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程,进程也是程序的一次执行过程,是系统运行程序的基本单位,系统运行一个程序即是一个进程从创建,运行到消亡的过程。
- 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
3.线程的调度
- 分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间
- 抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个执行(线程随机性),Java使用的为抢占式调度。
4.主线程
- JVM执行main方法,main方法会进入到栈内存JVM会找操作系统开辟一条main方法通向CPU的执行路径,CPU就可以通过这个路径来执行main方法而这个路径有一个名字,叫main(主)线程
5.创建线程
-
方法一:1.创建一个Thread类的子类。2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)3.创建Thread类的子类对象。4.调用Thread类中的方法start方法,开启新的线程,执行run方法。
-
注意事项:调用start方法线程开始执行,Java虚拟机调用该线程的run方法。2.结果是两个线程并发的运行,当前线程(main线程)和另一个线程(创建的新线程执行其run方法)。3.多次启动一个线程是非法的。特别是当线程已经结束执行之后,不能再重新启动。4.Java程序属于抢占式调度,哪个线程优先级高,哪个线程就先执行,优先级相同就会随机选择一个执行。
-
创建main主线程
package duox.xc;
public class DxcDome01 {
public static void main(String[] args) {
DxcDome02 dxcDome02 = new DxcDome02();
dxcDome02.start();//开启新线程
for (int i = 0; i <10 ; i++) {
System.out.println("main主方法执行了"+i);
}
}
}
- 创建新线程重写Thread类中的run方法
package duox.xc;
public class DxcDome02 extends Thread{
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
System.out.println("run方法执行了"+i);
}
}
}
- 运行结果
main主方法执行了0
run方法执行了0
main主方法执行了1
run方法执行了1
run方法执行了2
run方法执行了3
main主方法执行了2
run方法执行了4
run方法执行了5
run方法执行了6
run方法执行了7
run方法执行了8
run方法执行了9
main主方法执行了3
main主方法执行了4
main主方法执行了5
main主方法执行了6
main主方法执行了7
main主方法执行了8
main主方法执行了9
-
方法二:1.创建一个Runnable接口的实现类。2.在实现类中重写Runnable接口的run方法,设置线程任务。3.创建一个Runnable接口的实现类对象。4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象。5.调用Thread类中的start方法,开启新的线程执行run方法。
-
实现Runnable接口创建线程的好处:1.避免了单继承的局限性。2.增强了程序的可扩展性,降低了程序的耦合性(解耦)把设置线程任务和开启新线程进行了分离,在实现类中,重写run方法,用来设置线程任务。创建Thread类对象,调用start方法来开启新线程,对这两个步骤进行了分离
-
创建main主线程
package duox.xc;
public class Dxc001 {
public static void main(String[] args) {
Dxc002 dxc002 = new Dxc002();
Thread thread = new Thread(dxc002);
//thread.setName("ttt");//给线程设置名字
thread.start();
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+i);//获取线程名字
}
}
}
- 创建Runnable接口的实现类重写Runnable接口的run方法
package duox.xc;
public class Dxc002 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+i);//获取线程名字
}
}
}
- 运行结果
main0
Thread-00
main1
main2
Thread-01
main3
Thread-02
main4
Thread-03
main5
main6
main7
main8
main9
Thread-04
Thread-05
Thread-06
Thread-07
Thread-08
Thread-09
- 方法三:创建Callable接口的实现类重写Callable接口的call方法
- 创建main主线程
package duox.xc;
import java.util.concurrent.FutureTask;
public class Dxc0001 {
public static void main(String[] args) {
Dxc0002 dxc0002 = new Dxc0002();
//使用FutureTask封装Callable接口,用来处理返回值
FutureTask<Object> ft = new FutureTask<>(dxc0002);
//FutureTask接口是runnable接口的一个子接口
//所以new Thread(ft1,"thread01");构造方法创建thread对象
new Thread(ft).start();
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
- 创建Callable接口的实现类重写Callable接口的call方法
package duox.xc;
import java.util.concurrent.Callable;
public class Dxc0002 implements Callable<Object> {
@Override
public Object call() throws Exception {
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
return null;
}
}
- 运行结果
main0
main1
Thread-00
Thread-01
Thread-02
main2
main3
main4
main5
main6
Thread-03
Thread-04
Thread-05
Thread-06
Thread-07
Thread-08
Thread-09
main7
main8
main9