目录
方式一 继承Thread类
1 步骤
1 创建一个类继承Thread类
2 重写run()方法,设置线程任务(开启线程要做什么)
3 new 对象,调用Thread类的start()方法 → 就会开启新的线程,执行之前写的run()方法了
java使用的为抢占式调度,优先级高的线程先使用CPU,如果优先级相同,就随机选择.
2 代码
package manyThreads;
public class MyThread extends Thread{
//重写run()方法,设置线程的任务
@Override
public void run() {
//循环20次
for (int i = 0; i < 20; i++) {
System.out.println("run"+i);
}
}
}
package manyThreads;
public class MainMethod {
public static void main(String[] args) {
//新线程
MyThread myThread = new MyThread();
myThread.start();
//主线程
for (int i = 0; i < 20; i++) {
System.out.println("main"+i);
}
}
}
结果
3 程序执行分析
1 JVM 执行main方法,操作系统OS开辟了一条 main方法通向CPU的路径,这个路径就叫做 main线程(主线程)
2 当new MyThread(),调start()方法时,OS又开辟了一条新的到CPU的路径,这个路径就是 新线程MyThread,新线程会执行run()方法
3 对于CPU来说就有了2条路径,CPU就有了选择的权利,CPU喜欢谁就执行哪条路径,所以就有了程序的随机打印结果
(两个线程:一个main线程,一个新线程,就会抢夺CPU的执行权,谁抢到了谁执行对应的代码)
注意:
调用Thread类的start()方法,才会开启新的线程路径
如果直接执行run()方法,还是用的原来的线程
4 Thread类常用方法
4.1 获取线程的名称
方法1:Thread类的getName()方法
方法2:Thread.currentThread().getName()
主线程默认名称:main
新线程默认名称:Thread-0 Thread-1 Thread-2 Thread-3 ...
4.2 设置线程的名称(了解)
方法1:setName()
方法2:创建一个带参的构造方法,把线程名称传递给父类让父类给子线程起个名字
package manyThreads;
import androidx.annotation.NonNull;
public class MyThread extends Thread{
public MyThread() {
}
//方法2:创建一个带参的构造方法,把线程名称传递给父类让父类给子线程起个名字
public MyThread(@NonNull String name) {
super(name);
}
//重写run()方法,设置线程的任务
@Override
public void run() {
//获取线程的名称
System.out.println(getName());
}
}
package manyThreads;
public class MainMethod {
public static void main(String[] args) {
//方法一:setName()
MyThread myThread = new MyThread();
myThread.setName("小名");
myThread.start();
//方法二:创建一个带参的构造方法,把线程名称传递给父类让父类给子线程起个名字
MyThread myThread2 = new MyThread("阿树");
myThread2.start();
}
}
运行结果
4.3 暂停线程:sleep()
使当前正在执行的线程暂停指定的毫秒,毫秒数结束之后,线程继续执行
执行结果:隔1s打印一个数字
*方法二 : 实现Runnable接口
1 步骤
1 创建一个类,实现Runnable接口
2 重写run()方法,设置线程任务
3 new Runnable接口的实现对象
4 创建一个Thread类对象,构造方法中传递Runnable接口的实现对象
5 调用Thread类的start()方法
2 代码
package manyThreads;
public class MyThreadRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"之"+i);
}
}
}
package manyThreads;
public class MainMethod {
public static void main(String[] args) {
MyThreadRunnable myThreadRunnable = new MyThreadRunnable();
Thread thread = new Thread(myThreadRunnable);
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"之"+i);
}
}
}
执行结果
两种方式的比较
实现Runnable接口的好处
1 避免的单继承的局限性 (一个类只能继承一个类,一个人只能有1个亲爹)
实现Runnable接口还可以继承其他类,实现其他接口
2 增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口 把设置线程任务和开启新线程进行了分离
设置线程任务:Runnable接口中重写run()方法
开启新线程:创建的Thread类调用start()方法
匿名内部类实现线程的方法
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类的作用:简化代码
匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
匿名内部类的格式:
new 父类/接口(){
重写父类/接口中的方法
}
代码
package nimingThread;
import manyThreads.MyThreadRunnable;
public class MainMethod {
public static void main(String[] args) {
//1 线程的父类是Thread
new Thread() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "继承");
}
}
}.start();
//2 线程的接口是Runnable
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "实现接口");
}
}
}).start();
}
}
结果