记录了一些Java多线程demo

多线程

Thread

​ 通过继承Thread类重写run函数来建立多线程,优点是操作简单,缺点是无法继承其他类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();


for (int i = 0; i < 5; i++) {
System.out.println("主线程: " + i);
}
}
}

class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程: " + i);
}
}
}

Runnable

​ 通过实现Runnable接口实现多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();


for (int i = 0; i < 10; i++) {
System.out.println("主线程:" + i);
}
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程:" + i);
}
}
}

Callable

​ 通过实现Callable接口实现多线程,优点是能获取线程返回的值

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
package 多线程;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ThreadDemo3 {
public static void main(String[] args) {
Callable<String> c = new MyCallable();
FutureTask<String> f = new FutureTask<>(c);
Thread t = new Thread(f);
t.start();

try{
System.out.println(f.get());
}catch (Exception e){
e.printStackTrace();
}
}
}

class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "这是子线程";
}
}
Thread常用方法 作用
public void run() 子线程运行代码
public void start() 启动子线程
public String getName() 获取子线程名称
public void setName(String name) 设置子线程名称
public static Thread currentThread() 获取当前执行的线程对象
public static Thread sleep(int time) 子线程休眠
public final void join() 将子线程插入当前主线程之前执行

线程同步

​ 由于子线程执行是无序,当两个子线程同时执行时有可能出现线程安全问题。比如两个人同时抢同一张车票,前一个人将车票买走还没更新时被另一个人再买一次,那么同一个车票就就会被两个人同时购买。线程同步则是解决线程安全问题的方案。

同步代码块

​ 通过将核心代码上锁实现同步,同一时间只有一个线程可以执行代码块里的内容,其他线程将会堵塞等待。

1
2
3
synchronized (sdx){        //sdx为锁对象,同步锁支队锁对象相同的进程有效。
核心代码
}

同步方法

1
2
3
public synchronized void drawMoney(){
... ...
}

lock锁

1
2
3
Lock lk = new ReentrantLock();
lk.look;
lk.unlook; //将unlook放进finally当出现异常时也能解锁

线程通讯

方法名称 说明
void wait() 让当前线程等待并释放锁
void notify() 唤醒一个等待的线程
void notifyAll() 唤醒所有等待的线程
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 消费者线程
public class ConsumerThread extends Thread{
private Desk desk;
public ConsumerThread(Desk desk, String name){
super(name);
this.desk = desk;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
this.desk.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

// 生产者线程
public class MakeThread extends Thread{
private Desk desk;
public MakeThread(Desk desk,String name){
super(name);
this.desk = desk;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
this.desk.put();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
// Desk
public class Desk {
private String data;

public synchronized void get() throws InterruptedException {
String name = Thread.currentThread().getName();
if (data == null){
this.notifyAll();
this.wait();
} else {
System.out.println(name + "吃了" + data);
data = null;
this.notifyAll();
this.wait();
}
}

public synchronized void put() throws InterruptedException {
String name = Thread.currentThread().getName();
if (data == null){
data = name + "制作的包子";
System.out.println(name + "制作了一个包子");
this.notifyAll();
this.wait();
}else {
this.notifyAll();
this.wait();
}
}
}
// Test
public class Test {
public static void main(String[] args) {
Desk desk = new Desk();
new MakeThread(desk, "康师傅").start();
new MakeThread(desk, "吴师傅").start();
new MakeThread(desk, "谢师傅").start();

new ConsumerThread(desk, "付先生").start();
new ConsumerThread(desk, "赵先生").start();
}
}

线程池

​ 由于创建新线程开销比较大,线程过多会影响性能,线程池为解决该问题而存在

ThreadPoolExecutor参数 说明
corePoolSize 指定线程池核心线程的数量
maximumPoolSize 指定线程池的最大线程数量
keepAliveTime 指定临时线程的存活时间
unit 指定临时线程存活的时间单位
workQueue 指定线程池的任务对列
threadFactory 指定线程池的线程工厂
handler 指定线程池的任务拒绝策略
任务策略 说明
ThreadPoolExcutor.AbortPolicy 丢弃任务并抛出RejectedExecutionException异常
ThreadPoolExcutor.DiscardPolicy 丢弃任务,但不抛出异常
ThreadPoolExcutor.Discardldestiscardldestolicy 抛弃任务中等待最久的任务,然后把当前任务加入队列
ThreadPoolExcutor.CallerRunsPolicy 由主线程负责调用任务的run()方法从而绕过线程池直接执行

执行Runnable任务

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
import java.util.concurrent.*;

public class ThreadPoolExecutorDemo1 {
//LinkedBlockingDeque 列表的任务对列
//ArrayBlockingQueue 数组的任务对列
public static void main(String[] args) {
ExecutorService pool = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
}
}

执行Callable任务

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
39
40
41
42
43
import java.util.concurrent.*;

public class ThreadPoolExecutorDemo2 {
//LinkedBlockingDeque 列表的任务对列
//ArrayBlockingQueue 数组的任务对列
public static void main(String[] args) {
ExecutorService pool = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
Future<String> f1 = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
return "Thread.currentThread().getName()";
}
});
Future<String> f2 = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
return "Thread.currentThread().getName()";
}
});
Future<String> f3 = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
return Thread.currentThread().getName().toString();
}
});
try {
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}

工具类Executors创建线程池

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
import java.util.concurrent.*;

public class ExecytorsDemo {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "执行任务" + i);
}
}
});
}
}

方法 说明
public static ExecutorService newFixedThreadPool(int number) 创建固定线程数量的进程池,如果某进程执行异常结束则会补充一个新进程
public static ExecutorService newSingleThreadExecutor() 创建一个只有一个线程的进程池,如果该进程执行异常结束则会补充一个新进程
public static ExecutorService newCachedThreadPool 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲60s则会被回收掉
public static ExecutorService newScheduledThreadPool(int corePoolSize) 创建一个进程池,可以实现在给定延迟后运行任务或者定期执行任务

!!! 使用Executors可能会出现系统风险!!!