文章目录
- 1. 多线程的创建和启动
- 2. Thread 类
- 3. 创建多线程的两种方式
- 3.1.继承Thread类实现多线程
- 3.1.1. 举例
- 3.1.2. 举例2
- 3.2. 实现Runnable接口
- 3.2.1. 举例1
- 3.2.2. 举例2
- 4. 继承方式和实现方式的联系与区别
- 5. 使用多线程的优点
1. 多线程的创建和启动
Java 语言的 JVM 允许程序运行多个线程,它通过 java.lang.Thread
类来实现。
Thread
类的特性
每个线程都是通过某个特定 Thread 对象的 run()
方法来完成操作的,经常把 run()
方法的主体称为线程体;
通过该 Thread 对象的 start()
方法来调用这个线程
run():想要在开启的多线程中运行的代码逻辑,就写到run方法里
start():用来启动线程,本质上就是开始运行run方法
2. Thread 类
构造方法
Thread()
:创建新的 Thread 对象
Thread(String threadname)
:创建线程并指定线程实例名
Thread(Runnable target)
:指定创建线程的目标对象,它实现了 Runnable接口中的 run 方法
Thread(Runnable target, String name)
:创建新的 Thread 对象
3. 创建多线程的两种方式
3.1.继承Thread类实现多线程
步骤:
(1)定义子类继承 Thread 类。
(2)子类中重写 Thread 类中的 run 方法。
(3)创建 Thread 子类对象,即创建了线程对象。
(4)调用线程对象 start 方法:启动线程,调用 run 方法。
3.1.1. 举例
子类TestThread继承Thread类
package day15;
/**
* 继承Thread的方式实现多线程
* @author 14532
*
*/
public class TestThread extends Thread{
@Override
public void run() {
System.out.println("多线程运行的代码");
for(int i = 0; i <5; i++) {
System.out.println("这是多线程的逻辑代码:" + i);
}
}
}
Test.java
package day15;
public class Test {
public static void main(String[] args) {
Thread t0 = new TestThread();
t0.start();//启动线程
System.out.println("--------------1------------");
System.out.println("--------------2------------");
System.out.println("--------------3------------");
/**
* 多次运行这个main方法之后
* 我们发现main方法中打印的3行与开启线程运行run方法中的打印语句是混合起来的
* 而且main方法中的打印与run方法中打印语句顺序是不固定的
* 为什么?
* 因为main执行t0.start()方法开启多线程之后,就相当于在main方法之外开启一个支流
* 这个时候t0.start()的之后的main方法的其他代码的运行就与run方法运行无关了
*
* 以当前代码为例
* t0.start()的之后的main方法的其他代码与run方法的代码并行运行
* 就像两条河流一样,各走各的
* 那么控制台输出的结果就是两条并行程序运行的结果的总和,这个结果需要拆成两部分看
* 就可以看到,各自保持自己的输出顺序
* 这个就是多线程的异步,这个异步相对于执行t0.start()主程序来说的
* 简单来说就是开启了线程之后run方法中运行的代码和主程序中t0.start()之后的程序是并行执行的,没有先后关系
*/
}
}
运行结果:(注意每次运行的结果未必相同)
结果1:
结果2:
3.1.2. 举例2
注意:Test.java可以开启多个线程,比如再创建 t1、t2 两个线程
package day15;
public class Test {
public static void main(String[] args) {
Thread t0 = new TestThread();
t0.start();//启动线程
Thread t1 = new TestThread();
t1.start();
Thread t2 = new TestThread();
t2.start();
System.out.println("--------------1------------");
System.out.println("--------------2------------");
System.out.println("--------------3------------");
}
}
运行结果:(其中一种结果)
3.2. 实现Runnable接口
步骤:
(1)定义子类,实现 Runnable 接口。
(2)子类中重写 Runnable 接口中的 run 方法。
(3)通过 Thread 类含参构造器创建线程对象。
(4)将 Runnable 接口的子类对象作为实际参数传递给Thread 类的构造方法中。
(5)调用 Thread 类的 start 方法:开启线程,调用Runnable 子类接口的 run 方法。
3.2.1. 举例1
new Thread(new TestRunnable());
子类实现 Runnable 接口,重写 Runnable 接口中的 run 方法
package day15;
/**
* 通过实现Runnable接口方式实现多线程
* @author 14532
*
*/
public class TestRunnable implements Runnable{
@Override
public void run() {
System.out.println("Runable多线程运行的代码");
for(int i = 0; i <5; i++) {
System.out.println("这是Runable多线程的逻辑代码:" + i);
}
}
}
Test.java
package day15;
public class Test {
public static void main(String[] args) {
Thread t3 = new Thread(new TestRunnable());
t3.start();
System.out.println("--------------1------------");
System.out.println("--------------2------------");
System.out.println("--------------3------------");
}
}
运行结果:(注意每次运行的结果未必相同)
结果1:
结果2:
3.2.2. 举例2
Thread t4 = new Thread(new TestRunnable(), "t-1");
子类实现 Runnable 接口,重写 Runnable 接口中的 run 方法
package day15;
/**
* 通过实现Runnable接口方式实现多线程
* @author 14532
*
*/
public class TestRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":Runable多线程运行的代码");
for(int i = 0; i <5; i++) {
System.out.println(Thread.currentThread().getName() + ":这是Runable多线程的逻辑代码:" + i);
}
}
}
Test.java
package day15;
public class Test {
public static void main(String[] args) {
Thread t4 = new Thread(new TestRunnable(), "t-1");
t4.start();
Thread t5 = new Thread(new TestRunnable(), "t-2");
t5.start();
System.out.println("--------------1------------");
System.out.println("--------------2------------");
System.out.println("--------------3------------");
}
}
运行结果:
结果2:
使用
new Thread(new TestRunnable(), "t-1")
这种方法能后知道运行的是哪一种线程。
4. 继承方式和实现方式的联系与区别
区别:
- 继承 Thread: 线程代码存放 Thread 子类 run 方法中。重写 run 方法
- 实现 Runnable :线程代码存在接口的子类的 run 方法。实现 run 方法
实现接口方式的好处:
- 避免了单继承的局限性;
- 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
注:一般使用实现接口方式来实现多线程
举例:
package day15;
/**
* 通过实现Runnable接口方式实现多线程
* @author 14532
*
*/
public class TestRunnable implements Runnable{
int count = 0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":Runable多线程运行的代码");
for(int i = 0; i <5; i++) {
count++;
System.out.println(Thread.currentThread().getName() + ":这是Runable多线程的逻辑代码:" + count);
}
}
}
Test.java
package day15;
public class Test {
public static void main(String[] args) {
Runnable run = new TestRunnable();
Thread t4 = new Thread(run, "t-1");
t4.start();
Thread t5 = new Thread(run, "t-2");
t5.start();
System.out.println("--------------1------------");
System.out.println("--------------2------------");
System.out.println("--------------3------------");
}
}
运行结果(其中一种):
5. 使用多线程的优点
多线程程序的优点:
①提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
②提高计算机系统 CPU 的利用率。
③改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。(解释如下)
如果在一个方法里有1000行代码,前300行、中间300行、后400行这三段代码没有因果关系,这种情况我们就可以使用线程处理,把前中后三段代码分别放在不同线程中去运行,这样三段代码就是并行运行的。