Java并发练习

本文最后更新于:2022年7月14日 晚上

概览:Java并发练习

基础知识

函数 作用 其他
isAlive() 判断当前线程是否还存活
join() 等待一个线程死亡
Thread.yield() 使得当前线程放弃执行权
interrupt() 将线程状态标记为中断
isInterrupted() 判断是否被中断
Thread.interrupted() 判断是否被中断,可消除中断标记

三个任务打印1,2,3 如何让输出有序?

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
public class MyTask implements Runnable{

private int integer;

private Thread thread;

public void setInteger(int integer) {
this.integer = integer;
}

public void setThread(Thread thread) {
this.thread = thread;
}

@Override
public void run() {
if(thread != null){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(integer);
}
}

主方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Main {
public static void main(String[] args) {
// 创建三个任务
MyTask task1 = new MyTask();
MyTask task2 = new MyTask();
MyTask task3 = new MyTask();
// 创建三个线程
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task2);
Thread t3 = new Thread(task3);
// 设定三者顺序
task1.setInteger(1);
task2.setInteger(2);
task2.setThread(t1);
task3.setInteger(3);
task3.setThread(t2);

// 执行
t1.start();
t2.start();
t3.start();
}
}

控制多个任务执行顺序

任务1,2,3 可以并发执行,4在前三个执行完成后执行,然后5,6,7三个任务执行。

任务

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
public class Tasks implements Runnable{
private int integer;

public Tasks() {
}

public Tasks(int integer) {
this.integer = integer;
}

public int getInteger() {
return integer;
}

public void setInteger(int integer) {
this.integer = integer;
}

@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(integer);
}
}

执行

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
public class Main {
public static void main(String[] args) {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4,8,10, TimeUnit.SECONDS,new LinkedBlockingDeque<>());
Tasks task1 = new Tasks(1);
Tasks task2 = new Tasks(2);
Tasks task3 = new Tasks(3);
Tasks task4 = new Tasks(4);
Tasks task5 = new Tasks(5);
Tasks task6 = new Tasks(6);
Tasks task7 = new Tasks(7);
// 执行任务1,2,3
threadPool.execute(task1);
threadPool.execute(task2);
threadPool.execute(task3);
// 等待执行完成,执行任务4
threadPool.shutdown();
while(!threadPool.isTerminated()){
}
Thread t4 = new Thread(task4);
t4.start();
try {
t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行任务5,6,7
threadPool = new ThreadPoolExecutor(4,8,10, TimeUnit.SECONDS,new LinkedBlockingDeque<>());
threadPool.execute(task5);
threadPool.execute(task6);
threadPool.execute(task7);
threadPool.shutdown();
while(!threadPool.isTerminated()){
}
System.out.println("执行结束");
}
}
  • 疑问?shutdown之后还能重启吗?还是必须要创建一个新的线程池。

生产者与消费者 - Synchornized

自定义数据类

1
2
3
4
5
6
7
8
9
10
11
public class MyData {
private String data;

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}
}

生产者

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
public class Producer implements Runnable{

private MyData myData;

public Producer(MyData myData) {
this.myData = myData;
}

@Override
public void run() {
int count = 0;
while(true){
synchronized (myData){
if(myData.getData() == null){
System.out.println("生产数据" + ++count);
myData.setData(count+"");
}
// 唤醒其他线程
myData.notify();
try {
// 使当前线程等待
myData.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

消费者

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
public class Consumer implements Runnable{

private MyData myData;

public Consumer(MyData myData) {
this.myData = myData;
}

@Override
public void run() {
while(true){
synchronized (myData){
if(myData.getData() != null){
System.out.println("消费数据" + myData.getData());
myData.setData(null);
}
// 唤醒生产者线程
myData.notify();
try {
// 使得当前线程等待
myData.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

启动

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
public static void main(String[] args) {
MyData data = new MyData();
Producer producer = new Producer(data);
Consumer consumer = new Consumer(data);
// 创建两个线程
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);

t1.start();
t2.start();
}
}

生产者与消费者 - Lock&Condition

数据类

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
public class Messge {

private Lock lock = new ReentrantLock();
// 两个条件,一个控制生产者,一个控制消费者
private Condition prodCondition = lock.newCondition();
private Condition consCondition = lock.newCondition();

private String message;

public void setMessage(String message) throws InterruptedException {
lock.lock();
try{
while(this.message != null){
prodCondition.await();
}
this.message = message;
System.out.println("生产数据: " + this.message);
// 唤醒消费者线程
consCondition.signalAll();
}finally {
lock.unlock();
}
}

public String getMessage() throws InterruptedException {
lock.lock();
try {
while(this.message == null){
consCondition.await();
}
System.out.println("消费数据: " + this.message);
// 唤醒生产者
prodCondition.signalAll();
return this.message;
}finally {
this.message = null;
lock.unlock();
}
}
}

使用

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
public class Main {
public static void main(String[] args) {
Messge messge = new Messge();
Thread t1 = new Thread(()->{
for(int i = 0;i < 10;i++) {
try {
messge.setMessage("消息" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(()->{
for(int i = 0;i < 10;i++) {
try {
System.out.println(messge.getMessage());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

t1.start();
t2.start();
}
}

不可重入锁的例子

synchornized以及ReentrantLock都是可重入锁,表示一个锁可以重复使用,那么如何编写一个不可重入的锁呢?

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
public class UnReentrantLock implements Lock {

// 记录当前获取锁的线程
private Thread thread;

@Override
public void lock() {
synchronized (this){
// 同一时刻只有一个线程能执行
while(thread != null){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 绑定当前线程
thread = Thread.currentThread();
}
}

@Override
public void unlock() {
synchronized (this){
if(thread != Thread.currentThread()){
return;
}
// 解绑线程
thread = null;
notifyAll();
}
}

@Override
public void lockInterruptibly() throws InterruptedException {

}

@Override
public boolean tryLock() {
return false;
}

@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}

@Override
public Condition newCondition() {
return null;
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {
public static void main(String[] args) {
Lock lock = new UnReentrantLock();
lock.lock();
try {
System.out.println("获取锁,执行");
lock.lock();
try {
System.out.println("第二次获取锁,执行");
}finally {
lock.unlock();
}
}finally {
lock.unlock();
}
}
}

读写锁实现并发容器

https://www.bilibili.com/video/BV1Z54y1j7JT?p=29


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!