一个进程在运行时,至少有一个线程在运行。
public class HasOneThreadTest { public static void main(String[] args) { Thread thread = Thread.currentThread(); System.out.println(thread.getName()); } }
|
上面代码的运行结果是输出了 main,这个 main 是当前运行的线程和线程名字,和 main 方法的那个 main 没什么关系。
# 通过继承 Thread 创建线程
public class MyThreadTest { private static class MyThread extends Thread { @Override public void run() { System.out.println("当前线程是:" + Thread.currentThread().getName()); } }
public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.run(); myThread.start(); System.out.println("main方法线程名:" + Thread.currentThread().getName()); } }
|
运行结果:
直接调用线程的 run 方法,就跟平常调用类的方法没什么两样,其实还是在主线程中执行的,就不能通过新线程来执行。
启动新线程执行,得用 start()
方法。
# 线程运行具有随机性
public class MyThreadTest { private static class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { System.out.println("当前线程是:" + Thread.currentThread().getName()); } }
public static void main(String[] args) { MyThread t1 = new MyThread("T1"); MyThread t2 = new MyThread("T2"); MyThread t3 = new MyThread("T3"); t1.start(); t2.start(); t3.start(); } }
|
运行结果:
调用 start 方法后:
- 调用 start 之后,程序会通知 jvm,告诉 jvm 可以运行了
- jvm 异步的调用这个线程对应的 run 方法
- jvm 什么时候运行 run 方法,以及先运行哪个线程的 run 方法,这个是没法绝对控制的 (但是可以相对控制)
- start 方法的调用顺序,不代表线程的 run 方法的运行顺序。
# 通过实现 Runnable 创建线程
public class MyRunnableThreadTest { private static class MyRunnable implements Runnable { @Override public void run() { System.out.println("当前线程是:" + Thread.currentThread().getName()); } } public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); System.out.println("main线程中执行的代码:" + Thread.currentThread().getName()); } }
|
但是 Runnable 是一个函数式接口,可以用 Lamdba 表达式:
public class MyRunnableThreadTest { public static void main(String[] args) { Thread thread = new Thread(()->{ System.out.println("当前线程是:" + Thread.currentThread().getName()); }, "runnable"); thread.start(); System.out.println("main end"); } }
|
效果:
# 通过 Callable 接口创建线程
Java5 开始,Java 提供了 Callable 接口,这个接口怎么看都像是 Runnable 接口的增强版,Callable 接口提供了一个 call () 方法可以作为线程执行体,但 call () 方法比 run () 方法功更强大。call () 方法可以有返回值,call () 方法可以抛出异常。
public class MyCallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Integer> callable = () -> { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } System.out.println("当前线程是:" + Thread.currentThread().getName() + ",返回值是:" + sum); return sum; }; Set<FutureTask<Integer>> futureTasks = new HashSet<>(); for (int i = 0; i < 10; i++) { FutureTask<Integer> futureTask = new FutureTask<>(callable); futureTasks.add(futureTask); new Thread(futureTask, "T" + i).start(); } int result = 0; for (FutureTask<Integer> futureTask : futureTasks) { result += futureTask.get(); } System.out.println("最终的结果是:" + result); } }
|
效果:
# 三种线程实现方法的区别
1,采用 Thread 方式实现的线程不能继承其他父类,采用 Runnable 和 Callable 接口的可以继承其他父类,但是编程上采用 Thread 的方式可以直接使用 getName () 方法,而采用 Runnable 和 Callable 接口的方式需要先获取 Thread.currentThread ();
2, 采用 Runnable 和 Callable 的方式,可以多个线程公用一个 Target 对象,而采用 Thread 的方式不能,所以非常适合多个相同线程来处理同一份资源的情况
3,如果需要线程有返回值的需要使用 Callable 的方式。