线程实现的几种方式
1、继承Thread类
import java.util.*;
public class Test {
/**
* 打字员线程,每秒打出多少字
*/
class Typist extends Thread {
@Override
public void run() {
int wordNum = new Random().nextInt(5);
for(int i=1;i<=5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName() + "在第" + i + "秒打了" + wordNum + "个字");
}
}
}
public void printStart() {
Thread typist1 = new Typist();
typist1.setName("打字员A");
Thread typist2 = new Typist();
typist2.setName("打字员B");
Thread typist3 = new Typist();
typist3.setName("打字员C");
typist1.start();
typist2.start();
typist3.start();
}
public static void main(String[] args) {
/**
* 主线程结束
* 打字员A在第1秒打了4个字
* 打字员B在第1秒打了2个字
* 打字员C在第1秒打了4个字
* 打字员C在第2秒打了4个字
* 打字员B在第2秒打了2个字
* 打字员A在第2秒打了4个字
* 打字员A在第3秒打了4个字
* 打字员C在第3秒打了4个字
* 打字员B在第3秒打了2个字
* 打字员A在第4秒打了4个字
* 打字员B在第4秒打了2个字
* 打字员C在第4秒打了4个字
* 打字员B在第5秒打了2个字
* 打字员C在第5秒打了4个字
* 打字员A在第5秒打了4个字
*/
new Test().printStart();
System.out.println("主线程结束");
}
}
2、实现Runnable接口(推荐方式)
import java.util.*;
public class Test {
/**
* 打字员线程,每秒打出多少字
*/
class Typist implements Runnable {
@Override
public void run() {
int wordNum = new Random().nextInt(5);
for(int i=1;i<=5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "在第" + i + "秒打了" + wordNum + "个字");
}
}
}
public void printStart() {
Typist typist1 = new Typist();
Thread t1 = new Thread(typist1);
Typist typist2 = new Typist();
Thread t2 = new Thread(typist2);
Typist typist3 = new Typist();
Thread t3 = new Thread(typist3);
t1.setName("打字员A");t2.setName("打字员B");t3.setName("打字员C");
t1.start();t2.start();t3.start();
}
public static void main(String[] args) {
new Test().printStart();
System.out.println("主线程结束");
}
}
3、实现Callable接口,可以从线程中获取返回值
import lombok.Data;
import java.util.*;
import java.util.concurrent.*;
public class Test {
/**
* 打字员线程,每秒打出多少字
*/
@Data
class Typist implements Callable<Integer> {
private String name;
@Override
public Integer call() throws Exception {
int wordCount = 0;
int wordNum = new Random().nextInt(5);
for(int i=1;i<=5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wordCount += wordNum;
System.out.println(this.getName() + "在第" + i + "秒打了" + wordNum + "个字");
}
return wordCount;
}
}
public void printStart() throws ExecutionException, InterruptedException {
Typist t1 = new Typist();
t1.setName("打字员A");
FutureTask<Integer> futureTask1 = new FutureTask<>(t1);
Thread thread1 = new Thread(futureTask1);
thread1.start();
Typist t2= new Typist();
t2.setName("打字员B");
FutureTask<Integer> futureTask2 = new FutureTask<>(t2);
Thread thread2 = new Thread(futureTask2);
thread2.start();
System.out.println(t1.getName() + "一共打了" + futureTask1.get() + "个字");//get()方法阻塞
System.out.println(t2.getName() + "一共打了" + futureTask2.get() + "个字");
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Test().printStart();
System.out.println("主线程任务结束");
}
}
FutureTask.get()方法阻塞,程序的运行后,最后打印【主线程任务结束】
4、Callable接口+线程池(推荐方式,可以从线程中获取返回值)
import lombok.Data;
import java.util.*;
import java.util.concurrent.*;
public class Test {
/**
* 打字员线程,每秒打出多少字
*/
@Data
class Typist implements Callable<Integer> {
private String name;
@Override
public Integer call() throws Exception {
int wordCount = 0;
int wordNum = new Random().nextInt(5);
for(int i=1;i<=5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wordCount += wordNum;
System.out.println(this.getName() + "在第" + i + "秒打了" + wordNum + "个字");
}
return wordCount;
}
}
public void printStart() throws ExecutionException, InterruptedException {
//固定大小线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
Typist t1 = new Typist();
t1.setName("打字员A");
Typist t2 = new Typist();
t2.setName("打字员B");
Typist t3 = new Typist();
t3.setName("打字员C");
Future<Integer> f1 = executorService.submit(t1);//非阻塞
Future<Integer> f2 = executorService.submit(t2);
Future<Integer> f3 = executorService.submit(t3);
executorService.shutdown();
System.out.println(t1.getName() + "一共打了" + f1.get() + "个字") ;//阻塞
System.out.println(t2.getName() + "一共打了" + f2.get() + "个字") ;
System.out.println(t3.getName() + "一共打了" + f3.get() + "个字") ;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Test().printStart();
System.out.println("主线程任务结束");
}
}
Future.get()方法阻塞等待t1线程结束,获取线程执行完成后的返回值
应用场景:这种方式适合大数据量计算时,开启多个线程分别执行部分数据,最后通过get()方法的返回值再合并各个线程计算结果,经典的map-reduce