多线程编程

多线程编程

0x01 生产者和消费者问题

1.BlockingQueue 阻塞队列实现

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
// 生产者
class Producer implements Runnable {
private final BlockingQueue<Integer> queue;

public Producer(BlockingQueue queue) {
this.queue = queue;
}

@Override
public void run() {
while (true) {
try {
queue.put(produce());
System.out.println(Thread.currentThread().getName() + " put a message, total = " + queue.size());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private int produce() {
int x = (int) (Math.random() * 10);
System.out.println(Thread.currentThread().getName() + " put: " + x);
return x;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 消费者
class Consumer implements Runnable {
private final BlockingQueue<Integer> queue;

Consumer(BlockingQueue q) {
queue = q;
}

public void run() {
try {
while (true) {
System.out.println(Thread.currentThread().getName() + " take...");
consume(queue.take());
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}

void consume(int x) {
System.out.println(Thread.currentThread().getName() + " take a message :" + x + ", total = " + queue.size());
}
}
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingDeque<>(3);
Producer cooker = new Producer(blockingQueue);
Consumer waiter = new Consumer(blockingQueue);
ExecutorService s = Executors.newFixedThreadPool(5);
s.submit(cooker);
s.submit(cooker);
s.submit(cooker);
s.submit(waiter);
s.submit(waiter);
}

2.使用Object的wait/notify方法实现

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
82
83
84
85
86
87
88
public class 消费者模式2 {
public static void main(String[] args) {
WorkBench wb = new WorkBench();
Waiter waiter = new Waiter(wb);
Cooker cooker = new Cooker(wb);
new Thread(cooker, "厨师1号").start();
new Thread(cooker, "厨师2号").start();
new Thread(cooker, "厨师3号").start();
new Thread(waiter, "服务员1号").start();
new Thread(waiter, "服务员2号").start();
}
}

// 生产者:厨师 -> 做菜
class Cooker implements Runnable {
WorkBench wb;

public Cooker(WorkBench wb) {
this.wb = wb;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wb.put();
}
}
}

// 消费者:服务员 -> 取菜
class Waiter implements Runnable {
WorkBench wb;

public Waiter(WorkBench wb) {
this.wb = wb;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wb.take();
}
}
}

// 产品队列:(类似 BlockingQueue)
class WorkBench {
public static final int MAX = 3;
private volatile int queue = 0;

public synchronized void put() {
while (queue >= MAX) {
System.out.println(String.format("%s waiting...", Thread.currentThread().getName()));
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue++;
System.out.println(String.format("%s put()一盘菜,队列还有%d盘菜", Thread.currentThread().getName(), queue));
notifyAll();
}

public synchronized void take() {
while (queue <= 0) {
System.out.println(String.format("%s waiting...", Thread.currentThread().getName()));
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue--;
System.out.println(String.format("%s take()一盘菜,队列还剩%d盘菜", Thread.currentThread().getName(), queue));
notifyAll();
}
}

3.使用ReentrantLock的await/signal实现

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class 消费者模式3 {
public static void main(String[] args) {
WorkBench wb = new WorkBench();
Waiter waiter = new Waiter(wb);
Cooker cooker = new Cooker(wb);
new Thread(cooker, "厨师1号").start();
new Thread(cooker, "厨师2号").start();
new Thread(cooker, "厨师3号").start();
new Thread(waiter, "服务员1号").start();
new Thread(waiter, "服务员2号").start();
}
}

// 生产者:厨师 -> 做菜
class Cooker implements Runnable {
WorkBench wb;

public Cooker(WorkBench wb) {
this.wb = wb;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(new Random().nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
wb.put();
}
}
}

// 消费者:服务员 -> 取菜
class Waiter implements Runnable {
WorkBench wb;

public Waiter(WorkBench wb) {
this.wb = wb;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
wb.take();
}
}
}

// 产品队列:(类似 BlockingQueue)
class WorkBench {
public static final int MAX = 4;
private volatile int queue = 0;

private final ReentrantLock lock = new ReentrantLock();
final Condition full = lock.newCondition();
final Condition empty = lock.newCondition();

public void put() {
lock.lock();
while (queue >= MAX) {
System.out.println(String.format("%s waiting...", Thread.currentThread().getName()));
try {
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue++;
System.out.println(String.format("%s put()一盘菜,队列还有%d盘菜", Thread.currentThread().getName(), queue));
empty.signalAll();
lock.unlock();
}

public void take() {
lock.lock();
while (queue <= 0) {
System.out.println(String.format("%s waiting...", Thread.currentThread().getName()));
try {
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue--;
System.out.println(String.format("%s take()一盘菜,队列还剩%d盘菜", Thread.currentThread().getName(), queue));
full.signalAll();
lock.unlock();
}
}

0x02 多线程打印ABCD

题目描述:

有4个线程和1个公共的字符数组。
线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,
线程3的功能就是向数组输出C,线程4的功能就是向数组输出D。
要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定。

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
82
83
84
85
import java.util.Scanner;

public class PrintABCD {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int n = in.nextInt();
startPrintABCD(n);
}
}

public static void startPrintABCD(int n) {
sb = new StringBuffer();
Object a = new Object();
Object b = new Object();
Object c = new Object();
Object d = new Object();
Thread t1 = new Thread(new Task(n, a, b, 'A', 0));
Thread t2 = new Thread(new Task(n, b, c, 'B', 1));
Thread t3 = new Thread(new Task(n, c, d, 'C', 2));
Thread t4 = new Thread(new Task(n, d, a, 'D', 3));
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(sb.toString());
// System.out.println(sb.length());
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private static StringBuffer sb;

static class Task implements Runnable {
int n;
Object self, target;
char ch;
int id;

public Task(int n, Object self, Object target, char ch, int id) {
this.n = n;
this.self = self;
this.target = target;
this.ch = ch;
this.id = id;
}

@Override
public void run() {
// System.out.println("Task" + id + " run...");
while (n-- > 0) {
synchronized (self) {
while (sb.length() % 4 != id) {
waitSelf();
}
sb.append(ch);
notifyTarget();
waitSelf();
}
}
notifyTarget();
// System.out.println("Task" + id + " stop...");
}

private void waitSelf() {
try {
self.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private void notifyTarget() {
synchronized (target) {
target.notify();
}
}
}
}
作者

Dench

发布于

2020-08-21

更新于

2020-08-21

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×