一、线程
1、线程是什么?
线程(thread)是一个程序内部的一条执行路径。
我们之前启动程序执行后,main方法的执行其实就是一条单独的执行路径。
public static void main(String[] args) {
// 代码…
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 代码...
}
程序中如果只有一条执行路径,那么这个程序就是单线程的程序。
2、多线程是什么?
多线程是指从软硬件上实现多条执行流程的技术。
多线程用在哪里,有什么好处?
再例如:消息通信、淘宝、京东系统都离不开多线程技术。提高了办事效率。
3、关于多线程需要学会什么
二、多线程的创建
Thread类
- Java是通过java.lang.Thread 类来代表线程的。
- 按照面向对象的思想,Thread类应该提供了实现多线程的方式。
当有很多线程在执行的时候,我们怎么去区分这些线程呢?
此时需要使用Thread的常用方法:getName()、setName()、currentThread()等。
① Thread获取和设置线程名称
② Thread类获得当前线程的对象
注意!!
1、此方法是Thread类的静态方法,可以直接使用Thread类调用。
2、这个方法是在哪个线程执行中调用的,就会得到哪个线程对象。
③ Thread的构造器
④ Thread类的线程休眠方法
总结
Thread常用方法
Thread构造器
1、多线程的实现方案一:继承Thread类
- 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
- 创建MyThread类的对象
- 调用线程对象的start()方法启动线程(启动后还是执行run方法的)
方式一优缺点:
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于扩展
代码测试
我的线程类
package ThreadTest;
public class MyThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThread:"+i);
}
test();
}
public void test(){
System.out.println("1111111");
}
}
多线程测试
package ThreadTest;
public class ThreadTest2 {
public static void main(String[] args) {
// 创建多线程方式1 继承Thread类
Thread my = new MyThread2();
my.start();// start 表示的是启动当前线程
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest:"+i);
}
}
}
2、多线程的实现方案二:实现Runnable接口
- 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
- 创建MyRunnable任务对象
- 把MyRunnable任务对象交给Thread处理。
- 调用线程对象的start()方法启动线程
Thread的构造器
方式二优缺点:
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。
多线程的实现方案二:实现Runnable接口(匿名内部类形式)
- 可以创建Runnable的匿名内部类对象。
- 交给Thread处理。
- 调用线程对象的start()启动线程。
代码测试
package ThreadTest;
public class ThreadTest3 {
public static void main(String[] args) {
// 方式一
// MyRunnable my = new MyRunnable();
// 方式二 1.使用匿名内部类 2.lamda表达式
Thread thread = new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"蓝鸟");
thread.start();
MyThread2 myThread2 = new MyThread2("青鸟");
myThread2.start();
}
}
//class MyRunnable implements Runnable{
//
// @Override
// public void run() {
// for (int i = 0; i < 10; i++) {
// System.out.println("MyRunnable"+i);
// }
// }
//}
3、多线程的实现方案三:利用Callable、FutureTask接口实现。
- 得到任务对象
- 定义类实现Callable接口,重写call方法,封装要做的事情。
- 用FutureTask把Callable对象封装成线程任务对象。
- 把线程任务对象交给Thread处理。
- 调用Thread的start方法启动线程,执行任务
- 线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。
FutureTask的API
方式三优缺点:
- 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
可以在线程执行完毕后去获取线程执行的结果。 - 缺点:编码复杂一点。
代码测试
package ThreadTest;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTest4 {
/**
* 使用的是 Callable FutureTask
* 1.创建任务对象
* ①
* ② * *
* 2.把任务 交给线程来处理
* 3.启动线程
* 4.获取线程执行结果
*
* */ public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable call = new MyCallable();
FutureTask<String> task = new FutureTask<>(call);
Thread thread = new Thread(task);
thread.start();
int s = getSum();
System.out.println(Thread.currentThread().getName()+":"+s);
// Object obj = task.get();
// System.out.println(obj);
Integer sum1 = Integer.parseInt((String)task.get());// task.get() 调用此方法就会等到任务执行完毕
System.out.println("最终的结果是:"+(s+sum1));
System.out.println(1111111111111111L);
System.out.println(66666666666666L);
}
public static int getSum(){
int s = 0;
for (int i = 0; i < 200; i++) {
s+=i;
}
return s;
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
int s = sum();
System.out.println(Thread.currentThread().getName()+":"+s);
return String.valueOf(s);
}
public int sum(){
int s = 0;
for (int i = 1; i <= 100; i++) {
s+=i;
}
return s;
}
}
三、总结
3种方式对比