Java 多线程
多线程
概念
创建多线程三种方式
继承Thread类创建线程(不推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13// 通过继承Thread类重写run方法的方式
class Runner extends Thread{
public void run(){
}
}
public void start(){
Runner runner1 = new Runner();
runner1.setName("参数1");
runner1.start();
}实现Runnable接口创建线程(不推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13class Runner implements Runnable{
public void run(){
}
}
public void start(){
Runner runner1 = new Runner();
Thread t1 = new Thread(runner1);
t1.setName("参数1");
t1.start();
}实现Callable接口创建线程(推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Runner implements Callable<Integer> {
public Integer call() throws Exception {
return 0;
}
}
public void start() throws ExecutionException, InterruptedException {
// 线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runner runner1 = new Runner();
runner1.name = "参数1";
// 返回值
Future<Integer> r1 = executorService.submit(runner1);
// 所有线程执行结束后关闭线程池,释放资源
executorService.shutdown();
}三种创建方式对比
- 继承Thread,Java对继承不友好,不推荐使用。
- 实现Runnable接口,Java编程友好,但无法返回执行后的数据。
- 实现Callable接口,Java编程友好,可以返回多线程执行结果,稍显复杂,需要线程池。
线程同步
synchronized(同步锁)关键字的作用就是利用一个特定的对象设置一个锁lock(钥匙),在多线程(多名游客)并发访问的时候,同时只允许一个线程(一个游客)可以获得这个锁,执行特定的代码(如进入参观)。执行后释放锁,继续由其他线程争抢。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39class Printer {
// 定义锁对象
Object lock = new Object();
public void print() {
synchronized (lock) {
try {
Thread.sleep(500);
System.out.print("荷");
Thread.sleep(500);
System.out.print("塘");
Thread.sleep(500);
System.out.print("月");
Thread.sleep(500);
System.out.print("色");
System.out.println();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class PrintTask implements Runnable{
Printer printer;
public void run() {
printer.print();
}
}
public void start(){
Printer printer = new Printer();
// 创建5个线程
for (int i = 0; i < 5; i++) {
PrintTask task = new PrintTask();
task.printer = printer;
Thread thread = new Thread(task);
thread.start();
}
}Synchronized锁对象
synchronized代码块 - 任意对象即可
1
2
3
4
5
6
7
8
9
10// synchronized代码块演示
class Printer {
// 定义锁对象
Object lock = new Object();
public void print() {
synchronized (lock) {
}
}
}synchronized方法 - this当前对象
1
2
3
4
5
6
7// synchronized方法演示
// this关键字
class Printer {
public synchronized void print() {
}
}synchronized静态方法 - 该类的字节码对象
1
2
3
4
5
6
7// synchronized静态方法演示
// Printer.class字节码对象
class Printer {
public static synchronized void print() {
}
}
线程安全问题与解决方式
问题:如商城超售情况。
解决:使用synchronized锁机制解决。
线程池
包路径:java.util.concurrent(简称:JUC)
概念:并发是伴随着多核处理器的诞生而产生的,为了充分利用硬件资源,诞生了多线程技术。但是多线程又存在资源竞争的问题,引发了同步和互斥的问题,JDK1.5推出的java.util.concurrent(并发工具包)来解决这些问题。
Runnable接口弊端
- Runnable新建线程,性能差。
- 线程缺乏统一管理,可能无限制新建线程,相互竞争,严重时将占用过多系统资源从而导致死机或内存溢出问题。
线程池 - 线程复用
ThreadPool线程池(重用、可控、额外功能)
- 重用存在的线程,减少线程对象创建、消亡的开销。
- 线程总数可控,提高资源利用率。
- 提供额外功能:定时执行、定期执行、监控等。
JUC支持的线程池种类
在JUC中,提供了工具类Executors(调度器)对象来创建线程池,可创建以下4种线程池:
FixedThreadPool - 定长线程池
特点:固定线程总数,有空闲则执行,没有空闲则等待。
1
2
3
4
5
6
7
8
9
10
11ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 500; i++) {
int index = i;
executorService.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
}
executorService.shutdown();CachedThreadPool - 可缓存线程池
特点:无限大,有空闲线程则利用起来。没有闲置则创建新的线程。
1
2
3
4
5
6
7
8
9
10
11ExecutorService executorService = Executors.newCacheThreadPool();
for (int i = 0; i < 500; i++) {
int index = i;
executorService.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
}
executorService.shutdown();SingleThreadExecutor - 单线程池
特点:只有一个线程,通过排队执行。
1
2
3
4
5
6
7
8
9
10
11ExecutorService executorService = Executors.newSingleThreadPool();
for (int i = 0; i < 500; i++) {
int index = i;
executorService.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
}
executorService.shutdown();ScheduledThreadPool - 调度线程池
特点:根据一定频率,时长定时执行某一任务。
1
2
3
4
5
6
7ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(new Date() + "延迟1秒执行,间隔3秒执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CodeWhale-Blog!
评论








