02-线程的三种创建方式
![](https://img2018.cnblogs.com/i-beta/1517394/201911/1517394-20191105153707927-1477435603.png)
Thread类的方法
普通方法:
void run( ) - 若使用Runnable接口作为参数创建了线程对象,则调用该接口中被重写以后的run()方法;否则该方法什么也不做就直接返回。
void start( ) - 使得线程启动起来,java虚拟机会自动调用该线程的run()方法。
1.继承Thread 类
//1) 定义类继承Thread public class SubThread extends Thread {
//2)重写run()方法, run()方法体中的代码就是子线程要执行的代码 @Override public void run() {
//在子线程,打印100行字符串 for(int i = 1; i<101; i++){ System.out.println("sub thread : " + i); } } }
测试
package com.mmonkey1024; public class Test { public static void main(String[] args) { // SubThread subThread = new SubThread(); // 形成多态 Thread thread = new SubThread(); // 创建线程 thread.start(); //重点: 调用run()也会执行,但是这样做 并没有 开启一个线程!!! // thread.run(); for(int i = 1; i <= 5; i++) { System.out.println("执行主线程中的循环: "+i); } } }
结果:
执行主线程中的循环: 1 执行主线程中的循环: 2 子线程中的循环: 1 执行主线程中的循环: 3 子线程中的循环: 2 执行主线程中的循环: 4 子线程中的循环: 3 子线程中的循环: 4 子线程中的循环: 5 执行主线程中的循环: 5
2.实现Runnable 接口
实现Runnable 接口 再重写run()方法
package com.mmonkey1024; //1) 定义Runnable接口的实现类 public class Prime implements Runnable { //2)重写run()方法, run方法体就是用户线程执行的代码 @Override public void run() { for(int i = 1; i<=10; i++){ System.out.println("子线程 : " + i); } } }
测试类
package com.mmonkey1024; //1) 定义Runnable接口的实现类 public class Prime implements Runnable { //2)重写run()方法, run方法体就是用户线程执行的代码 @Override public void run() { for(int i = 1; i<=10; i++){ System.out.println("子线程 : " + i); } } }
或者 使用匿名内部类
package com.mmonkey1024; public class Test{ public static void main(String[] args) { //在调用方法时,实参是接口匿名内部类对象 Thread t1 = new Thread(new Runnable() { //在匿名内部类中重写接口抽象方法 @Override public void run() { //指定子线程要执行的代码 for(int i = 1; i<=100; i++){ System.out.println("t1线程 : " + i); } } }); t1.start(); // 开启t1线程 Thread t2 = new Thread(new Runnable() { @Override public void run() { //指定子线程要执行的代码 for(int i = 1; i<=100; i++){ System.out.println("t2线程 : " + i); } } }); t2.start(); // 开启t2线程 // main线程 for (int i = 1; i <= 100; i++) { System.out.println("main线程 " + i); } } }
3.实现Callable 接口
//Callable接口中的call()有返回值, 通过Callable泛型 指定返回值的类型
//Runnable接口中的run()方法没有返回值 , Callable接口的call()有返回值
package com.mmonkey1025; import java.util.Random; import java.util.concurrent.Callable; //1) 定义类实现Callable接口 public class Prime implements Callable<Integer> { //2)重写抽象方法call()方法 @Override public Integer call() throws Exception { int result = new Random().nextInt(100); System.out.println("执行子线程, 完成某个计算, 结果为: " + result); return result; } }
测试类
package com.mmonkey1025; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Test { public static void main(String[] args) throws InterruptedException, ExecutionException { //1.创建线程对象 Prime prime = new Prime() ; //创建Callable接口实现类对象 FutureTask<Integer> task = new FutureTask<>(prime); //FutureTask实现了RunnableFuture<V>接口,该接口继承了Runnable接口, FutureTask类就是Runnable接口实现类 Thread t3 = new Thread(task); //2.开启新的线程 t3.start(); // System.out.println("当前线程是main线程,可以获得子线程的执行结果:"); System.out.println("result=" + task.get()); } }
分析一下::
Thread t = new Thread( ); // 创建Thread类型的引用 指向 Thread 自己的对象:只能调用本类内部的run()方法
t.run( );
t.start( );
//若希望 调用上面重写之后的run()方法,则需要使用接口引用作为参数的方式
// 接口类型的引用 指向了实现类的对象,形成了多态
Thread t = new Thread( new SubRunnable() );
t.start( ); // 通过Thread类型的引用,调用start()方法,运行阶段会自动调用实现类中重写后的run()方法
三,线程的原理分析
扩展:使用匿名内部类 的技术来实现上述前2种创建 和 启动线程的方式:
4.使用匿名内部类 创建线程
1. 将继承的方式改为 匿名内部类的策略实现
public class NoNameStartTest {
public static void main(String[] args) {
// 1. 将继承的方式改为 匿名内部类的策略实现
new Thread() {
@Override
public void run() {
System.out.println("十月秋风天气凉,可惜没钱买衣裳.....");
}
}.start(); // 开启线程
}
}
结果:
十月秋风天气凉,可惜没钱买衣裳.....
2.将接口的方式改为 匿名内部类的策略实现
package com.monkey1031;
public class NoNameStartTest {
public static void main(String[] args) {
// 2. 将接口的方式改为 匿名内部类的策略实现
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("十月秋风天气寒,可惜没钱买衣裳");
}
}).start(); // 开启线程
}
}
结果:
十月秋风天气寒,可惜没钱买衣裳
5.使用lambda表达式 创建线程