一:了解
1.什么是线程?
①线程(Thread)是一个程序内部的一条执行流程。
②程序中如果只有一条执行流程,那这个程序就是单线程的程序。
2.什么是多线程?
①多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。
②消息通信、淘宝京东系统都离不开多线程技术。
二:如何在程序中创建出多条线程?
1.Java是通过java.lang.Thread类的对象来代表线程的。
2.多线程的注意事项:
①启动线程必须是调用start方法,不是调用run方法。
②不要把主线程任务放在启动子线程之前。
3.多线程的创建
方式一:继承Thread类
①定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
②创建MyThread类的对象
③调用线程对象的start()方法启动线程(启动后还是执行run方法的)
方式一的优缺点:
·优点:编码简单
·缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("子线程运行"+i);
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for (int i = 0; i < 10000; i++) {
System.out.println("主线程运行"+i);
}
}
}
方式二:实现Runnable接口
①定义一个线程任务类MyRunable实现Runable接口,重写run()方法
②创建MyRunable任务对象
③把MyRunable任务对象交给Thread处理。
Thread类提供的构造器:
Thread(Runable target) 封装Runable对象成为线程对象
④调用线程对象的start()方法启动线程
方式二的优缺点:
·优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
·缺点:需要多一个Runable对象。
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("子线程运行"+i);
}
}
}
public class ThreadTest2 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start();
for (int i = 0; i < 10000; i++) {
System.out.println("主线程运行"+i);
}
}
}
线程创建方式二的匿名内部类写法
①可以创建Runable的匿名内部类对象
②再交给Thread线程对象
③再调用线程对象的start()启动线程
public class ThreadTest2 {
public static void main(String[] args) {
//方式一:
// Runnable r = new Runnable() {
// @Override
// public void run() {
// for (int i = 0; i < 10000; i++) {
// System.out.println("子线程运行"+i);
// }
// }
// };
// Thread t = new Thread(r);
// t.start();
//方式二:
// Thread t = new Thread(new Runnable() {
// @Override
// public void run() {
// for (int i = 0; i < 10000; i++) {
// System.out.println("子线程运行"+i);
// }
// }
// });
// t.start();
//方式三:
Thread t = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
System.out.println("子线程运行"+i);
}
}
);
t.start();
for (int i = 0; i < 10000; i++) {
System.out.println("主线程运行"+i);
}
}
}
方式三:利用Callable接口,FutureTask类来实现。
①创建任务对象
·定义一个类实现Callable接口,重写call方法,封装要做的事情和要返回数据
·把Callable类型的对象封装成FutureTask(线程任务对象)
②把线程任务对象交给Thread对象
③调用Thread对象的start方法启动线程
④线程执行完毕后、通过FutureTask对象的get方法去获取线程任务执行的结果
FutureTask的API
构造器:
FutureTask<>(Callable call) 把Callable对象封装为FutureTask对象
方法:
get() 获取线程执行call方法返回的结果
线程三的优缺点
·优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果
·确定:编程复杂一点
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return "从1到"+n+"的结果是"+sum;
}
}
import java.util.concurrent.FutureTask;
public class ThreadTest3 {
public static void main(String[] args) throws Exception {
MyCallable mc = new MyCallable(100);
FutureTask<String> ft = new FutureTask<>(mc);
new Thread(ft).start();
//当执行到此处如果上方线程未执行完毕不会获取结果
//会先暂停等待
String s = ft.get();
System.out.println(s);
}
}
三:Thread的常用方法
1.Thread提供了很多与线程操作相关的方法
构造器:
Thread(String name) 可以为当前线程指定名称
Thread(Runnable target) 封装Runnable对象成为线程对象
Thread(Runable target, String name) 封装Runnable对象成为线程对象,并指定线程名称
方法:
run() 线程的任务方法
start() 启动线程
getName() 获取当前线程的名称,线程名称默认是Thread-索引
setName() 为线程设置名称
public static Thread currentHread() 获取当前执行的线程对象
public static void sleep(long tmie) 让当前执行的线程休眠多少毫秒后,再继续执行
join() 让调用当前这个方法的线程先执行完!可确保线程顺序执行完。
2.示例:
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
Thread t = Thread.currentThread();
for (int i = 0; i < 5; i++) {
System.out.println(t.getName()+"运行"+i);
}
}
}
public class ThreadTest4 {
public static void main(String[] args) throws Exception {
MyThread mt1 = new MyThread();
mt1.setName("线程一");
System.out.println(mt1.getName());
mt1.start();
mt1.join();
MyThread mt2 = new MyThread();
mt2.setName("线程二");
System.out.println(mt2.getName());
mt2.start();
mt2.join();
MyThread mt3 = new MyThread("线程三");
mt3.start();
mt3.join();
Thread t = Thread.currentThread();
t.setName("主线程");
System.out.println(t.getName());
}
}