多线程程序的优点:
- 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
- 提高计算机系统CPU的利用率
- 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改
何时需要多线程
1.程序需要同时执行多个任务
2.程序需要实现需要等待的任务,如用户输入、文件读写、网络操作等
3.需要一些后台运行的程序
创建线程和使用
Java的JVM允许程序运行多个线程,通过java.lang.Thread 类来体现。
创建线程的几种方式
1.创建一个Thread的子类并重写run方法,之后子类就可以实例化并start
- 定义子类继承Thread类。
- 子类中重写Thread类中的run方法。
- 创建Thread子类对象,即创建了线程对象。
- 调用线程对象start方法:启动线程,调用run方法。
注意一个线程只能start一次
/**
* 多线程的创建,继承Thread类方式
* 1) 定义子类继承Thread类。
* 2) 子类中重写Thread类中的run方法。将线程要执行的操作写在run方法中
* 3) 创建Thread子类对象,即创建了线程对象。
* 4) 调用线程对象start方法:启动线程,调用run方法。
*
* @author ycy
* @create 2020 - 07 -04 -3:27 下午
*/
//例子:遍历100内的偶数
//1.创建一个继承与Thread类的子类
class MyThread extends Thread {
//子类中重写Thread类中的run方法。
@Override
public void run() {
for(int i=0;i<1000;++i){
//fori为模版
if(i%2==0){
System.out.println(i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//创建子类对象
MyThread t1 = new MyThread();
//start方法
t1.start();
for (int i = 0; i < 100; i++) {
if(i%2!=0){
System.out.println("i = " + i);
}
}
System.out.println("hello");
}
}
thread的几种方法
void start(): 启动线程,并执行对象的run()方法
run(): 线程在被调度时执行的操作
String getName(): 返回线程的名称
void setName(String name):设置该线程名称
static Thread currentThread(): 返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类
static void yield():线程让步
暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
若队列中没有同优先级的线程,忽略此方法
join() :
当某个程序执行流中调用其他线程的 join() 方法时,调用线程将 被阻塞,直到 join() 方法加入的 join 线程执行完为止
低优先级的线程也可以获得执行
static void sleep(long millis):(指定时间:毫秒)
令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后 重排队。
抛出InterruptedException异常
stop(): 强制线程生命期结束,不推荐使用
boolean isAlive():返回boolean,判断线程是否还活着
sleep(long millis):阻塞一段时间
线程优先级
MAX_PRIORITY:10
MIN _PRIORITY:1
NORM_PRIORITY:5
getPriority() :返回线程优先值
setPriority(int newPriority) :改变线程的优先级
说明:线程创建时继承父线程的优先级
低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
2.实现Runable接口
- 定义子类,实现Runnable接口。
- 子类中重写Runnable接口中的run方法。
- 通过Thread类含参构造器创建线程对象。
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
- 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
/**
* 1) 定义子类,实现Runnable接口。
* 2) 子类中重写Runnable接口中的run方法。
* 3) 通过Thread类含参构造器创建线程对象。
* 4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
* 5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
* @author ycy
* @create 2020 - 07 -04 -5:56 下午
*/
class MyThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
public class ThreadTest2 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);
t1.start();
}
}
比较:
开发中优先选择实现接口的方式
原因:1.实现方式没有单继承的局限性
2.实现适合处理多线程有共享数据,数据放在实现的类中,以同一个对象来建造多个Thread类对象
联系:thread也实现了Runnable,都需要重写run方法
方式三:JDK5.0 实现Callable接口
与使用Runnable相比, Callable功能更强大些
相比run()方法,可以有返回值,重写call方法
方法可以抛出异常
支持泛型的返回值
需要借助FutureTask类,比如获取返回结果
Future接口
可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
FutrueTask是Futrue接口的唯一的实现类
FutureTask 同时实现了Runnable, Future接口。它既可以作为
Runnable被线程执行,又可以作为Future得到Callable的返回值
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author ycy
* @create 2020 - 07 -05 -7:50 下午
*/
//1.创建一个实现Callable的实现类
class NumThread implements Callable {
//2.实现call方法,将此线程需要执行的操作声明在call()方法中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++