目录
一、并发与并行
- 并发:指两个或多个事件在同一个时间段内发生。
- 并行:指两个或多个事件在同一时刻发生(同时发生)。
二、线程与进程
- 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
- 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
- 线程调度
- 分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
- 抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),java使用的为抢占式调度。
三、创建多线程
java.lang.Thread类:描述线程的类
3.1 创建 Thread 类的子类(方式一)
- 创建一个Thread类的子类
- 在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么?)
- 创建Thread类的子类对象
- 调用Thread类中的start方法,开启新的线程,执行run方法
void start() :使该线程开始执行;Java虚拟机调用该线程的 run 方法
结果是两个线程并发地运行;当前线程(main 线程)和另一个线程(创建的新线程,执行其run方法)
多次启动一个线程是非法的,特别是当线程已经结束执行后,不能再重新启动
MyThread1.java 线程类
package com.cpz.demo1_Thread;
// 创建一个Thread类的子类
public class MyThread1 extends Thread {
//在Thread类的子类中重写Thread类中的run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run :" + i);
}
}
}
Thread1Test.java 测试类
package com.cpz.demo1_Thread;
public class Thread1Test {
public static void main(String[] args) {
// 创建Thread类的子类对象
MyThread1 mt1 = new MyThread1();
// 调用Thread类中的start方法,开启新的线程,执行run方法
mt1.start();
for (int i = 0; i < 20; i++) {
System.out.println("main :" + i);
}
}
}
3.2 多线程原理简述
3.3 Thread类
- static Thread currentThread():返回对当前正在执行的线程对象的引用
- String getName():返回该线程的名称。
- 使用Thread类中的方法getName()
- 可以先获取到正在执行的线程,使用线程中的方法 getName() 获取线程的名称
- void setName(String name):设置线程的名称。
- 使用Thread类中的setName()方法
- 创建一个带参数的构造方法,参数传递线程的名称;调用父类的带参构造方法,把线程名称传递给父类,让父类(Thread)给子线程起一个名字:Thread(String name) 分配新的Thread对象
- public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
3.4 实现 Runnable 接口(方式二)
- 创建Runnable接口的实现类,
- 重写该接口的run()方法,设置线程任务
- 创建Runnable实现类的实例
- 创建Thread类对象,构造方法中传递Runnable接口的实现类对象。
- 调用Thread类中的start()方法,开启新的线程执行run方法。
MyThread2.java
package com.cpz.demo2_Thread;
public class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run: " + i);
}
}
}
Thread2Test.java
package com.cpz.demo2_Thread;
public class Thread2Test {
public static void main(String[] args) {
Runnable run = new MyThread2();
Thread t = new Thread(run);
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("main: " + i);
}
}
}
3.5 Thread 和 Runnable 的区别
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源
- 可以避免Java中的单继承的局限性
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立
- 线程池只能放入实现Runnable或者Callable类线程,不能直接放入继承Thread的类
补充:在Java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实就是在操作系统中启动了一个进程。
3.6 匿名内部类方式实现线程的创建
3.6.1 继承 Thread 类
package com.cpz.demo3_Thread;
public class NoNameInnerClassThread {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run: " + i);
}
}
}.start();
for (int i = 0; i < 20; i++) {
System.out.println("main: " + i);
}
}
}
3.6.2 实现 Runnable 接口
package com.cpz.demo3_Thread;
public class NoNameInnerClassThread2 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run: " + i);
}
}
};
new Thread(runnable).start();
for (int i = 0; i < 20; i++) {
System.out.println("main: " + i);
}
}
}