1. 创建线程有哪几种方式
创建线程有三种方式,分别是继承Thread类、实现Runnable接口、实现Callable接口。
通过继承Thread类来创建并启动线程的步骤如下:
-
定义Thread类的子类,并重写该类的run()方法,该run()方法将作为线程执行体。
-
创建Thread子类的实例,即创建了线程对象。
-
调用线程对象的start()方法来启动该线程。
通过实现Runnable接口来创建并启动线程的步骤如下:
-
定义Runnable接口的实现类,并实现该接口的run()方法,该run()方法将作为线程执行体。
-
创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread对象为线程对象。
-
调用线程对象的start()方法来启动该线程。
通过实现Callable接口来创建并启动线程的步骤如下:
-
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。然后再创建Callable实现类的实例。
-
使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
-
使用FutureTask对象作为Thread对象的target创建并启动新线程。
-
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
2. Thread类常用方法
Thread类常用构造方法:
-
Thread()
-
Thread(String name)
-
Thread(Runnable target)
-
Thread(Runnable target, String name)
其中,参数 name为线程名,参数 target为包含线程体的目标对象。
Thread类常用静态方法:
-
currentThread():返回当前正在执行的线程;
-
interrupted():返回当前执行的线程是否已经被中断;
-
sleep(long millis):使当前执行的线程睡眠多少毫秒数;
-
yield():使当前执行的线程自愿暂时放弃对处理器的使用权并允许其他线程执行;
Thread类常用实例方法:
-
getId():返回该线程的id;
-
getName():返回该线程的名字;
-
getPriority():返回该线程的优先级;
-
interrupt():使该线程中断;
-
isInterrupted():返回该线程是否被中断;
-
isAlive():返回该线程是否处于活动状态;
-
isDaemon():返回该线程是否是守护线程;
-
setDaemon(boolean on):将该线程标记为守护线程或用户线程,如果不标记默认是非守护线程;
-
setName(String name):设置该线程的名字;
-
setPriority(int newPriority):改变该线程的优先级;
-
join():等待该线程终止;
-
join(long millis):等待该线程终止,至多等待多少毫秒数。
3. run()和start()有什么区别?
run()方法被称为线程执行体,它的方法体代表了线程需要完成的任务,而start()方法用来启动线程。
调用start()方法启动线程时,系统会把该run()方法当成线程执行体来处理。但如果直接调用线程对象的run()方法,则run()方法立即就会被执行,而且在run()方法返回之前其他线程无法并发执行。也就是说,如果直接调用线程对象的run()方法,系统把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程执行体
4. join
join方法,让当前调用这个方法的线程的方法先执行完
线程的join()方法是用来实现线程之间的等待的。当一个线程调用了另一个线程的join()方法时,它会被阻塞,直到被调用join()方法的线程执行完毕才会继续执行。在你提供的引用中,[1]和都提到了这一点。
具体地说,当线程2调用线程1的join()方法时,线程2会被阻塞,直到线程1执行结束为止。这意味着线程2会等待线程1完成任务后再继续执行。这种机制可以用来确保线程的执行顺序或等待其他线程的结果。
总结起来,线程的join()方法可以用来实现线程之间的等待,以确保某个线程在其他线程执行完毕后再继续执行。