Java并发 2
uwupu 啦啦啦啦啦

创建线程,实现接口优于继承Thread

  1. Java不支持多继承,因此继承了Thread类就无法继承其他类;
  2. 类可能只要求可执行就可,继承Thread开销过大。

基础线程机制

Executor

Executor管理多个异步任务的执行,无需程序员显式地管理线程的生命周期。

目前有三种Executor:

  • CachedThreadPool:一个任务创建一个线程;
  • FixedThreadPool:所有任务使用固定数量的线程,多出来的排队或丢弃,取决于初始化参数;
  • SingleThreadExecutor:大小为1的FixedThreadPool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ExecutorStudy {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 30; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+" Execute.");
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}

Daemon

Daemon,即守护线程。

守护线程是程序运行时在后台提供服务的线程,不是程序中不可或缺的部分

当所有非守护线程结束时,程序也将终止,同时会杀死所有守护线程。

主线程不是守护线程;

使用setDaemon()可以设置一个线程为守护线程。

1
2
3
4
Thread thread = new Thread(() -> {
System.out.println("这即将是一个守护线程");
});
thread.setDaemon(true);//设置守护线程

sleep()

休眠当前线程为指定时间。

1
2
3
4
5
6
Thread thread = new Thread(() -> {
System.out.println("这是一个线程");
try {
Thread.sleep(3000);//线程休眠3秒
}catch (Exception e){e.printStackTrace();}
});

yield()

Thread.yield()表示当前线程已经完成了生命周期中最重要的部分。

这个方法只是给线程调度器一个建议,且只是建议具有相同优先级的其他线程可以运行。

1
2
3
4
Thread thread = new Thread(() -> {
System.out.println("这是一个线程");
Thread.yield();
});

线程中断

一个线程执行完毕后会自动结束,如果在运行过程中发生异常也会提前结束.

InterruptedException

当对一个线程使用了interrupt()方法,若线程处于阻塞、限期等待或无限期等待状态,就会抛出InterruptedException异常,从而提前结束该线程。

不能终端I/O阻塞和synchronized阻塞。

示例:sleep()限期阻塞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
int cnt = 0;
try {
while (true) {
System.out.println("执行 " + cnt++);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}, "一个线程");
thread.start();//启动线程
Thread.sleep(3500);//等待thread线程执行一会
thread.interrupt();//发出中断线程请求

}
1
2
3
4
5
6
7
8
9
10
执行 0
执行 1
执行 2
执行 3
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yn.ExecutorStudy.lambda$main$0(ExecutorStudy.java:37)
at java.lang.Thread.run(Thread.java:748)

Process finished with exit code 0

interrupted()

如果一个线程的run()无限循环且没有sleep()方法,此时调用interrupt()方法就无法使线程提前结束。

在线程内可以用interrupted()来获取线程是否执行过interrupt,在线程内控制是否接收interrupt中断。

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
int cnt = 0;
while (!Thread.interrupted()) {
System.out.println("执行 " + cnt++);
}
System.out.println("线程结束");
}, "一个线程");
thread.start();//启动线程
thread.interrupt();//发出中断线程请求
}

Executor的中断操作

Executor可以通过shutdown()方法或shutdownNow()方法来关闭Executor服务。

shutdown()会等待线程执行完毕后在进行服务关闭;

shutdownNow()会调用每个线程的interrupt方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ExecutorStudy2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
try {
while (true){
System.out.println("线程执行");
Thread.sleep(300);
}
}catch (Exception e){e.printStackTrace();}
System.out.println("线程结束");
});
executorService.shutdownNow();
}
}
1
2
3
4
5
6
7
8
9
线程执行
线程结束
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yn.ExecutorStudy2.lambda$main$0(ExecutorStudy2.java:13)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

通过submit()方法提交任务,可以获得一个Future对象,通过future对象可以独立控制单个线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<?> submit = executorService.submit(() -> {
try {
while (true) {
System.out.println("线程执行");
Thread.sleep(300);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程结束");
});
Thread.sleep(1000);
submit.cancel(true);//类似于interrupt()
executorService.shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
线程执行
线程执行
线程执行
线程执行
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yn.FutureStudy.lambda$main$0(FutureStudy.java:14)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
线程结束

Process finished with exit code 0

线程互斥同步

Java提供了两种锁机制来控制多个线程对共享资源的互斥访问。

  • JVM实现的synchronized 同步
  • JDK实现的ReentrantLock 可重入锁

synchronized

使用synchronized使用多个方式实现同步。

 评论