怎样建设一个韩国网站,系统的网站建设教程,去水印小程序搭建,哪里可以鉴定钻石三种线程创建方式
继承Thread类#xff0c;子类重写run#xff08;#xff09;方法#xff0c;调用子类的strat#xff08;#xff09;启动线程。实现Runnable接口#xff0c;实现run#xff08;#xff09;方法#xff0c;调用对象start#xff08;#xff09;启…三种线程创建方式
继承Thread类子类重写run方法调用子类的strat启动线程。实现Runnable接口实现run方法调用对象start启动线程。实现Callable接口实现call方法用FutureTask()封装实现类。使用FutureTask对象作为Thread对象调用start启动线程调用FutureTask对象的get方法获取返回值。
三种方式的优缺点
采用继承Thread类方式
优点编写简单。缺点因为线程类已经继承了Thread类所以不能再继承其他的父类。
采用实现Runnable接口方式
优点线程类只是实现了Runable接口还可以继承其他的类。缺点编程稍微复杂如果需要访问当前线程必须使用Thread.currentThread()方法。
Runnable和Callable的区别
Callable规定的方法是call(),Runnable规定的方法是run()。Callable的任务执行后可返回值而Runnable的任务是不能返回值得。Call方法可以抛出异常run方法不可以因为run方法本身没有抛出异常所以自定义的线程类在重写run的时候也无法抛出异常运行Callable任务可以拿到一个Future对象表示异步计算的结果。它提供了检查计算是否完成的方法以等待计算的完成并检索计算的结果。通过Future对象可以了解任务执行情况可取消任务的执行还可获取执行结果。
总结Runnable和Callable功能一样的都是构造线程执行的任务其区别可以简单理解为有无返回值的区别通常Callable使用的比较多
继承Thread类
继承Thread类的话必须重写run方法在run方法中定义需要执行的任务。
class MyThread extends Thread{private static int num 0;public MyThread(){num;}Overridepublic void run() {System.out.println(主动创建的第num个线程);}}
创建好了自己的线程类之后就可以创建线程对象了然后通过start()方法去启动线程。注意不是调用run()方法启动线程run方法中只是定义需要执行的任务如果调用run方法即相当于在主线程中执行run方法跟普通的方法调用没有任何区别此时并不会创建一个新的线程来执行定义的任务。
public class Test {public static void main(String[] args) {MyThread thread new MyThread();thread.start();}}class MyThread extends Thread{private static int num 0;public MyThread(){num;}Overridepublic void run() {System.out.println(主动创建的第num个线程);}}
在上面代码中通过调用start()方法就会创建一个新的线程了。为了分清start()方法调用和run()方法调用的区别请看下面一个例子
public class Test {public static void main(String[] args) {System.out.println(主线程ID:Thread.currentThread().getId());MyThread thread1 new MyThread(thread1);thread1.start();MyThread thread2 new MyThread(thread2);thread2.run();}}class MyThread extends Thread{private String name;public MyThread(String name){this.name name;}Overridepublic void run() {System.out.println(name:name 子线程ID:Thread.currentThread().getId());}}
运行结果
主线程ID:1
name:thread2 子线程ID:1
name:thread1 子线程ID:8
从输出结果可以得出以下结论
1thread1和thread2的线程ID不同thread2和主线程ID相同说明通过run方法调用并不会创建新的线程而是在主线程中直接运行run方法跟普通的方法调用没有任何区别
2虽然thread1的start方法调用在thread2的run方法前面调用但是先输出的是thread2的run方法调用的相关信息说明新线程创建的过程不会阻塞主线程的后续执行。
2.实现Runnable接口
定义runnable接口的实现类并重写该接口的run()方法该run()方法的方法体同样是该线程的线程执行体。 创建 Runnable实现类的实例并依此实例作为Thread的target来创建Thread对象该Thread对象才是真正的线程对象。 调用线程对象的start()方法来启动该线程。
package Thread;import java.util.concurrent.*;
//测试类
public class TestThread {public static void main(String[] args) throws Exception {testImplents();}public static void testImplents() throws Exception {MyThreadImplements myThreadImplements new MyThreadImplements();Thread t1 new Thread(myThreadImplements);Thread t2 new Thread(myThreadImplements, my thread -2);t1.start();t2.start();}
}
//线程类
class MyThreadImplements implements Runnable {Overridepublic void run() {System.out.println(通过实现Runable线程号: Thread.currentThread().getName());}
}
3. 使用Callable接口
和Runnable接口不一样Callable接口提供了一个call方法作为线程执行体call()方法比run()方法功能要强大。
创建并启动有返回值的线程的步骤如下 创建Callable接口的实现类并实现call()方法然后创建该实现类的实例从java8开始可以直接使用Lambda表达式创建Callable对象。使用FutureTask类来包装Callable对象该FutureTask对象封装了Callable对象的call()方法的返回值使用FutureTask对象作为Thread对象的target创建并启动线程因为FutureTask实现了Runnable接口调用FutureTask对象的get()方法来获得子线程执行结束后的返回值 下面是一个例子
public class Main {public static void main(String[] args){MyThread3 thnew MyThread3();//使用Lambda表达式创建Callable对象//使用FutureTask类来包装Callable对象FutureTaskInteger futurenew FutureTaskInteger((CallableInteger)()-{return 5;});new Thread(task,有返回值的线程).start();//实质上还是以Callable对象来创建并启动线程try{System.out.println(子线程的返回值future.get());//get()方法会阻塞直到子线程执行结束才返回}catch(Exception e){ex.printStackTrace();}}}
start和run的区别
具体区别可以看【Java面试题】线程中start方法和run方法的区别
start()方法用来开启线程但是线程开启后并没有立即执行他需要获取cpu的执行权才可以执行run()方法是由jvm创建完本地操作系统级线程后回调的方法不可以手动调用否则就是普通方法