正文:
线程是一种重要的概念,用于实现并发执行的多任务。
线程是程序执行的最小单元,它可以独立执行代码片段。
多线程允许在同一程序中同时执行多个任务,提高程序的并发性和响应能力。
创建线程的三种方式:
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;
}
@Override
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 接口:
方式需要注意的是,需要将实现类作为构造参数传递给 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 接口
为了能够获取线程的执行结果,我们可以通过实现 Callable 接口来实现多线程。与前面两种方式不同的是,我们需要使用线程池来调用 Callable 接口的实现类。首先,我们需要创建一个线程池,然后创建一个实现了 Callable 接口的类,将其代码放在线程中执行。
在使用线程池调用 Callable 接口的实现类时,有两种方法可供选择。一种是使用线程池的 execute 方法,这种方法没有返回值,与前面的方式效果相同。另一种是使用线程池的 submit 方法,这种方法有返回值,返回的是一个 Future
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 + "执行完毕!!!!!!!";
}
}
转载请注明:汇站网 » Java 线程是程序中执行的独立单元有三种创建线程的方式