一、线程创建的4种方式
1.1 继承Thread类的方式
public class MyThread01 extends Thread{
@Override
public void run() {
System.err.println("=== 子线程执行…… ===");
}
public static void main(String[] args) throws InterruptedException {
MyThread01 thread01 = new MyThread01();
thread01.start();
}
}
1.2 实现Runnable接口的方式
public class MyRunnableThread implements Runnable {
public void run() {
System.err.println("=== 子线程执行 ===");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnableThread());
thread.start();
}
}
1.3 匿名内部类的方式
public class AnonymousThread {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.err.println("=== sub thread executed... ===");
}
}).start();
}
}
1.4 基于线程池的方式
public class ExecutorServiceThread {
private static ExecutorService threadPool = Executors.newFixedThreadPool(3);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
threadPool.submit(new Runnable() {
public void run() {
System.err.println("=== "+Thread.currentThread().getName()+" ===");
}
});
}
}
}
执行效果:
=== pool-1-thread-1 ===
=== pool-1-thread-2 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-3 ===
=== pool-1-thread-2 ===
1.5 有返回值的线程创建
public class MyFutureTask implements Callable<String> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long l = System.currentTimeMillis();
MyFutureTask myFutureTask = new MyFutureTask();
FutureTask<String> task = new FutureTask<String>(myFutureTask);
Thread thread = new Thread(task);
thread.start();
System.err.println("主线程继续执行其他业务");
Thread.sleep(900);
System.err.println("主线程获取子线程执行结果:"+task.get()+",耗时:"+(System.currentTimeMillis() - l)+"ms");
}
@Override
public String call() throws Exception {
System.err.println("模拟耗时业务……");
Thread.sleep(1000);
return "succ";
}
}
执行效果;
主线程继续执行其他业务
模拟耗时业务……
主线程获取子线程执行结果:succ,耗时:1001ms
1.6 基于集合的流式编程的方式
通过Collection接口的parallelStream流来实现
public class ParallelStreamDemo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4);
// 并行打印
list.parallelStream().forEach(System.out::println);
// 并行转换并求和
int sum = list.parallelStream().mapToInt(value -> value).sum();
System.err.println("结果:"+sum);
}
}
执行效果:
2
1
3
4
结果:10
二、线程的中断:
通过查看Thread类下的方法可以看到,有一个被废弃的方法:stop();
那么,为什么stop()方法会被废弃呢,由于执行stop()方法并不释放当前线程所持有的锁等资源,这样的结果显然不是我们想要的,取而代之,jdk推出了线程中断(interrupt)的概念;
2.1 线程的中断:
目前在jdk中关停一个线程的逻辑是这样的:调用interrupt()只是将中断标志位置位,我们需要自行根据中断标志位来执行结束该线程、释放锁资源等操作;
Thread类下关于interrupt的方法有如下三个:
2.1.1 public void interrupt()方法
只是给当前线程标记一下中断标志位,实际上线程还是会继续执行;
2.1.1 public static boolean interrupted()方法
检查当前线程的中断标志位,返回boolean值(已中断true/未中断false),此方法会 清除 中断标志位,即:在仅被中断一次的情况下,连续调用2次interrupted()方法时,第一次返回true,第二次将会返回false;
2.1.1 public boolean isInterrupted()方法
检查当前线程的中断标志位,返回boolean值(已中断true/未中断false),此方法 不会清除 中断标志位。
类方法interrupted()与对象方法isInterrupted()底层都是调用了私有的isInterrupted(boolean ClearInterrupted)方法,只是前者在调用时传入true,后者传入false:
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
2.2 show me the code:
2.2.1 结束线程:
public class MyThread01 extends Thread{
@Override
public void run() {
while(!isInterrupted()){
System.err.println("=== 子线程执行中…… ===");
}
System.err.println("===线程中断,模拟释放锁资源,模拟结束进程===");
}
public static void main(String[] args) throws InterruptedException {
MyThread01 thread01 = new MyThread01();
thread01.start();
Thread.sleep(10);
thread01.interrupt();
}
}
执行效果:
=== 子线程执行中…… ===
=== 子线程执行中…… ===
=== 子线程执行中…… ===
=== 子线程执行中…… ===
=== 子线程执行中…… ===
===线程中断,模拟释放锁资源,模拟结束进程===
2.2.2 类方法interrupted() VS 对象方法isInterrupted()
public class InterruptCompare {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
myThread.interrupt();
}
}
class MyThread extends Thread{
@Override
public void run() {
while(!isInterrupted()){
// do something
}
// exit
System.err.println("第一次调用isInterrupted():"+isInterrupted());
System.err.println("第二次调用isInterrupted():"+isInterrupted());
System.err.println("第一次调用interrupted():"+Thread.interrupted());
System.err.println("第二次调用interrupted():"+Thread.interrupted());
}
}
执行结果:
第一次调用isInterrupted():true
第二次调用isInterrupted():true
第一次调用interrupted():true
第二次调用interrupted():false
三、补充:创建线程时,如果继承Thread类的同时,实现了Runnable接口,将会怎样呢?
3.1 show me the code
public class MultiThreadDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.err.println("=== this is from Runnable ===");
}
}){
@Override
public void run() {
System.err.println("=== this is from Thread ===");
}
}.start();
}
}
3.2 分析
要搞清楚这个问题,首先要梳理一下我们在new Thread(new Runnable(){...})的时候,到底发生了什么:
Runnable部分的实现将被忽略
3.3 结果验证
=== this is from thread ===