Java 提供了三种创建线程的方法:
-
通过继承 Thread 类本身;
-
通过实现 Runnable 接口;
-
通过 Callable 和 Future 创建线程(大学阶段做了解即可)。
通过继承Thread类来创建线程
通过重写的run方法和Thread类自带的start方法都可以开启线程,但两者的执行机制并不相同。
创建一个类继承Thread类并重写run()方法,该方法是新线程的入口点,调用start()方法开启线程
通过start方法开启线程
class Testthread extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println(i+"run");
}
}
}
public class Test {
public static void main(String[] args){
Testthread t=new Testthread();
t.start();
for(int i=0;i<100;i++)
{
System.out.println(i+"main");
}
}
}
可以发现主线程main()和线程Testthread在同时执行。
如果把start改为run则先执行完run()方法在执行主线程main()
所以要达到多线程即主线程和子线程并行,应该用start()方法来启动线程。
Thread类自带的一些方法
序号 | 方法描述 |
1 | public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
2 | public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 |
3 | public final void setName(String name) 改变线程名称,使之与参数 name 相同。 |
4 | public final void setPriority(int priority) 更改线程的优先级。 |
5 | public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 |
6 | public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。 |
7 | public void interrupt() 中断线程。 |
8 | public final boolean isAlive() 测试线程是否处于活动状态。 |
上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。
序号 | 方法描述 |
1 | public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
2 | ** public static void sleep(long millisec)** 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
3 | public static boolean holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
4 | public static Thread currentThread() 返回对当前正在执行的线程对象的引用。 |
5 | ** public static void dumpStack()** 将当前线程的堆栈跟踪打印至标准错误流。 |
即使调用了start方法,线程也不一定立即就会执行,由CPU来调度,决定线程的执行顺序
(还有1,2,3这个运行结果,不过我手残点没了)
可以发现即使t1最先调用start方法开启线程但t1不一定是第一个运行的线程,
线程运行的先后由CPU决定。
通过实现 Runnable 接口来创建线程
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。创建一个类实现Runable接口,并且实现run()方法,编写线程执行体,创建线程对象,调用start()方法启动线程。
实现Callable接口(大学作了解)
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值, 创建 Callable 实现类的实例,使用 Future 类来包装 Callable 对象,该 Future 对象封装了该 Callable 对象的 call() 方法的返回值,使用ExecutorService 对象作为 Thread 对象的 target 创建并启动新线程使用submit方法提交并执行,调用 Future 对象的 get() 方法来获得子线程执行结束后的返回值,最后关闭服务。
对前两种方法的总结:
继承Thread类:
子类继承Thread类具备多线程的能力
启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性
实现Runnable接口
实现接口Runnable具备多线程的能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承的局限性,可以多实现,灵活方便,方便一个对象被多个线程使用。