JAVA之多线程
什么是线程?
线程(Thread)是一个程序内部的一条执行流程。
什么是多线程?
多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)
如何创建多线程:
有两种方法可以创建新的执行线程。 一种是将类声明为Thread的子类。 此子类应覆盖类Thread的run方法。 然后可以分配和启动子类的实例(对象)。
多线程的创建方式一:继承Thread类
1.定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
2.创建MyThread类的对象
3.调用线程对象的start()方法启动线程(启动后还是执行run方法的)
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。
public class MyThread extends Thread {
// 重写run方法,定义线程执行的任务
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
public static void main(String[] args) {
// 创建线程对象
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 设置线程名称
thread1.setName("线程1");
thread2.setName("线程2");
// 启动线程
thread1.start();
thread2.start();
}
}
注意事项
1.启动线程必须是调用start方法,不是调用run方法
直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
只有调用start方法才是启动一个新的线程执行。
2、不要把主线程任务放在启动子线程之前
多线程的创建方式一:实现Runnable接口创建多线程
步骤:
1.定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
2.创建MyRunnable任务对象
3.把MyRunnable任务对象交给Thread处理
4.调用线程对象的start()方法启动线程
优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
缺点:需要多一个Runnable对象。
public class MyRunnable implements Runnable {
// 实现run方法,定义线程执行的任务
@Override
public void run() {
//for循环50次
for (int i = 0; i < 50; i++) {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行第"+i+"次");
}
}
public static void main(String[] args) {
// 创建Runnable对象
Runnable myRunnable = new MyRunnable();
// 创建Thread对象,并传入Runnable对象
Thread thread1 = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable);
// 设置线程名称
thread1.setName("线程1");
thread2.setName("线程2");
// 启动线程
thread1.start();
thread2.start();
}
}
匿名内部类的创建方式:
public class MyRunnable {
// 实现run方法,定义线程执行的任务
public static void main(String[] args) {
// 创建Runnable对象
Runnable myRunnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行第"+i+"次");
}
}
};
// 创建Thread对象,并传入Runnable对象
Thread thread1 = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable);
// 设置线程名称
thread1.setName("线程1");
thread2.setName("线程2");
// 启动线程
thread1.start();
thread2.start();
}
}
线程的创建方式三:实现callable接口
前两种线程创建方式都存在的一个问题假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果
JDK 5.0提供了Callable接口和FutureTask类来实现(多线程的第三种创建方式)
这种方式最大的优点:可以返回线程执行完毕后的结果,
1.创建任务对象:
定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
把Callable类型的对象封装成FutureTask(线程任务对象)。
2.把线程任务对象交给Thread对象
3.调用Thread对象的start方法启动线程,
4.线程执行完毕后、通过FutureTask对象的的qet方法去获取线程任务执行的结果。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ThreadDemo3 {
public static void main(String[] args) {
Callable<Integer> callable = new MyCallable();
/*未来任务对象的作用
a、本质是一个Runnable线程任务对象,可以交给Thread线程对象处理
b、可以获取线程执行完毕后的结果。*/
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
//获取futureTask返回结果
try {
//如果主线程没有执行完毕,则get()会阻塞主线程,直到get()返回结果为止
System.out.println(futureTask.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
//定义类并实现Callable接口
class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
}
callable的优缺点:
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
三种方式总结:
Thread的常用方法
Thread的常用方法 | 说明 |
---|---|
public void run() | 线程的任务方法 |
public void start() | 启动线程 |
public String getName() | 获取当前线程的名称,线程名称默认是Thread-索引 |
public String setNanme(String name) | 为线程设置名称 |
public static Thread currentThread() | 获取当前执行的线程对象 |
public static void sleep(long time) | 让当前执行的线程休眠多少毫秒后,再继续执行 |
public final void join()..... | 让调用当前这个方法的线程先执行完! |
Thread提供的常见构造器 | 说明 |
---|---|
public Thread(String name) | 可以为当前线程指定名称 |
public Thread(Runnable target) | 封装Runnable对象成为线程对象 |
public Thread(Runnable target,String name) | 封装Runnable对象成为线程对象,并指定线程名称 |
Thread类还提供了诸如:yield、interrupt、守护线程、线程优先级等线程的控制方法,在开发中很少使用。