共计 3398 个字符,预计需要花费 9 分钟才能阅读完成。
简介
线程是一种重要的概念,用于实现并发执行的多任务。
-
线程是程序执行的最小单元,它可以独立执行代码片段。
-
多线程允许在同一程序中同时执行多个任务,提高程序的并发性和响应能力。
-
线程可以共享内存空间,方便数据交换和通信。
三种方式创建线程
1. 继承Thread类
可以通过继承 Thread 类,并重写 run()
方法,在需要的地方调用 start
方法进行执行线程。
注意:需要调用 start
方法才能看见线程效果,调用 run
方法只是在当前线程同步执行 run 方法。
如果需要执行的逻辑代码只在一个地方出现,那么可以使用 Lambda 表达式的方式给
public class ThreadTest { | |
/** | |
* 继承自 Thread 的类 | |
* 1. 需要调用 start 方法才能看见线程效果,调用 run 方法只是在当前线程同步执行 run 方法 | |
*/ | |
public static void main(String[] args) { | |
new MyThread("线程1", 5).start(); | |
new MyThread("线程2", 2).start(); | |
} | |
} | |
class MyThread extends Thread { | |
int count; | |
MyThread(String name, int count){ | |
super(name); | |
this.count = count; | |
} | |
public void run() { | |
System.out.println(getName() + "开始执行,时间:" + new Date()); | |
try { | |
for (int i=0; i < count; i++){ | |
System.out.println(getName() + "第" + (i+1) + "次执行...."); | |
Thread.sleep(1000); | |
} | |
} catch (InterruptedException e) { | |
throw new RuntimeException(e); | |
} | |
System.out.println(getName() + "执行完毕,时间:" + new Date()); | |
} | |
} |
2. 实现Runnable接口
首先需要注意的是,实现 Runnable 接口的方式,其实还是要将实现类作为构造参数传递给 Thread 类,通过 Thread 的 start 方法开辟一个线程。
另外,Runnable 接口是一个函数式接口,可以通过 Lambda 表达式创建实现类。
public class RunnableTest { | |
/** | |
* 为什么需要通过Thread执行Runnable对象 | |
* 1. 线程管理:Thread类提供了对线程的管理和控制。它包含了一些方法,例如start()来启动线程,join()来等待线程完成, | |
* interrupt()来中断线程等。通过Thread类,可以更方便地控制线程的生命周期和执行。 | |
* 2. 线程调度:Thread类提供了线程调度的功能。线程调度是指决定线程执行顺序和时间片分配的过程。 | |
* 通过Thread类,可以设置线程的优先级、睡眠时间和调度策略等。 | |
* 3. 线程上下文:Thread类维护了线程的上下文信息,例如线程名称、线程状态、线程组等。 | |
* 通过Thread类,可以方便地获取和设置这些信息。 | |
*/ | |
public static void main(String[] args) { | |
MyRunnable runnable1 = new MyRunnable("线程1", 5); | |
Thread thread1 = new Thread(runnable1); | |
thread1.start(); | |
// Lambda 表达式创建线程 | |
new Thread(() -> { | |
System.out.println( "线程2开始执行,时间:" + new Date()); | |
try { | |
for (int i=0; i < 2; i++){ | |
System.out.println("线程2第" + (i+1) + "次执行...."); | |
Thread.sleep(1000); | |
} | |
} catch (InterruptedException e) { | |
throw new RuntimeException(e); | |
} | |
System.out.println("线程2执行完毕,时间:" + new Date()); | |
}).start(); | |
} | |
} | |
class MyRunnable implements Runnable { | |
private String name; | |
private int count; | |
MyRunnable(String name, int count) { | |
this.name = name; | |
this.count = count; | |
} | |
@Override | |
public void run() { | |
System.out.println(name + "开始执行,时间:" + new Date()); | |
try { | |
for (int i=0; i < count; i++){ | |
System.out.println(name + "第" + (i+1) + "次执行...."); | |
Thread.sleep(1000); | |
} | |
} catch (InterruptedException e) { | |
throw new RuntimeException(e); | |
} | |
System.out.println(name + "执行完毕,时间:" + new Date()); | |
} | |
} |
3. 实现Callable接口
前面两种方式都是通过重写 run 方法实现多线程,需要注意的是 run 方法返回值是 void,也就是说无法获取线程的执行结果,于是 Callable 出现了。
这种方式需要通过线程池的方式进行调用,首先需要创建一个线程池,然后创建一个 Callable 接口的实现类,使用线程池的 submit
或 execute
执行线程中的代码。
而这两个方法的区别是, execute
方法是无返回值的,效果和上面的方式一样。而 submit
是有返回值的,返回的是一个 Future<T>
接口类型的对象,通过该接口的 get 方法可以获取到返回值。
public class CallableTest { | |
/** | |
* | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
ExecutorService executor = Executors.newFixedThreadPool(2); | |
System.out.println("实际创建的线程池对象:" + executor); | |
Callable<String> task1 = new MyCallable("线程1", 5); | |
Future<String> future1 = executor.submit(task1); | |
System.out.println("实际创建的Future对象:" + future1); | |
Callable<String> task2 = new MyCallable("线程2", 2); | |
Future<String> future2 = executor.submit(task2); | |
executor.shutdown(); | |
try { | |
// 这里是阻塞的,需要等待获取结果 | |
String result1 = future1.get(); | |
System.out.println(result1); | |
// 虽然线程2比线程1早执行完,但是需要等待线程1执行完毕。如果放在线程1之前获取返回值,则先打印线程2执行完毕 | |
String result2 = future2.get(); | |
System.out.println(result2); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
class MyCallable implements Callable<String> { | |
private String name; | |
private int count; | |
public MyCallable(String name, int count) { | |
this.name = name; | |
this.count = count; | |
} | |
@Override | |
public String call() throws Exception { | |
//System.out.println(name + "开始执行,时间:" + new Date()); | |
for (int i=0; i < count; i++){ | |
System.out.println(name + "第" + (i+1) + "次执行...."); | |
Thread.sleep(1000); | |
} | |
//System.out.println(name + "执行完毕,时间:" + new Date()); | |
return name + "执行完毕!!!!!!!"; | |
} | |
} |
提醒:本文发布于620天前,文中所关联的信息可能已发生改变,请知悉!