前言
想象一下生活中哪些是和线程沾边的?饭店炒菜就是一个很好的例子
首先客人要吃菜,前提是厨师要炒好,也就是说,厨师不炒好的话客人是没有饭菜的。这时候,厨师就是一个线程,客人拿菜就是另一个线程。
工具
jdk13,IDEA2019.1.4
知识点
Thread、Runnable、synchronized、面向对象知识(继承、封装、接口、方法重写)、条件判断以及线程的一些其他知识点
设计思路
首先要有两个线程,也就是说要两个类,分别是Producer(生产者)和Consumer(消费者)。
由于我们是模拟厨师与客人之间的互动,也就是说还需要一个类来封装信息:Message(类)。
然后,避免线程之间发生数据混乱的情况,肯定还需要使用synchronized来进行线程同步。
具体步骤
首先我们来一份没有用synchronized的代码,先看看效果:
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
|
public class Message { private String title; private String content; Message(){ }; public Message(String title, String content) { this .title = title; this .content = content; } public String getTitle() { return title; } public void setTitle(String title) { this .title = title; } public String getContent() { return content; } public void setContent(String content) { this .content = content; } } /* * 定义生产者类Producer * */ class Producer implements Runnable{ private Message msg=null; public Producer(Message msg) { this.msg = msg; } @Override public void run() { for (int i=0;i<=50;i++){ if (i%2==0){ this.msg.setTitle("喜欢夜雨吗?"); try { Thread.sleep(100); }catch (InterruptedException e){ System.out.println(e); } this.msg.setContent("是的呢!"); }else { this.msg.setTitle("还不关注我吗?"); try { Thread.sleep(100); }catch (InterruptedException e){ System.out.println(e); } this.msg.setContent("好的呢!"); } } } } /* * 定义消费者类Consumer * */ class Consumer implements Runnable{ private Message msg= null ; public Consumer(Message msg) { this .msg = msg; } @Override public void run() { for ( int i= 0 ;i<= 50 ;i++){ try { Thread.sleep( 100 ); } catch (InterruptedException e){ System.out.println(e); } System.out.println( this .msg.getTitle()+ "--->" + this .msg.getContent()); } } } class TestDemo{ public static void main(String[] args) { Message msg= new Message(); new Thread( new Producer(msg)).start(); new Thread( new Consumer(msg)).start(); } } |
看看运行结果:
看仔细咯,发生了数据错乱啊,Title与Content没有一一对应欸。咋办?
能咋办,改代码呗。
发生数据混乱的原因完全是因为,生产者线程还没生产的时候,消费者就已经消费了(至于消费的啥我也不知道,我也不敢问啊)。所以造成了数据混乱,不过我们上面说了啊,要使用synchronized来让线程同步一下。但是又会出问题,我们接着往下看
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
|
class TestDemo{ public static void main(String[] args) { Message msg= new Message(); new Thread( new Producer(msg)).start(); new Thread( new Consumer(msg)).start(); } } class Message{ private String title,content; public synchronized void set(String title,String content){ this .title=title; this .content=content; } public synchronized void get(){ try { Thread.sleep( 1000 ); } catch (InterruptedException e){ System.out.println(e); } System.out.println( this .title+ "-->" + this .content); } public String getContent() { return content; } public void setContent(String content) { this .content = content; } public String getTitle() { return title; } public void setTitle(String title) { this .title = title; } } class Producer implements Runnable{ private Message msg= null ; Producer(Message msg){ this .msg=msg; } @Override public void run() { for ( int i= 0 ;i<= 50 ;i++){ if (i% 2 == 0 ){ this .msg.set( "喜欢夜雨吗?" , "是的呢!" ); } else { this .msg.set( "还不关注吗?" , "好的呢!" ); } } } } class Consumer implements Runnable{ private Message msg= null ; Consumer(Message msg){ this .msg=msg; } @Override public void run() { for ( int i= 0 ;i<= 50 ;i++){ this .msg.get(); } } } |
我又重新封装了一些方法,然后运行的时候,wc,数据倒是不混乱了,但是呢,数据重复了一大堆。
为啥会出现这个问题呢?最后想了一下,会出现这种问题的,就是因为线程的执行顺序的问题。我们想要实现的效果是生产者线程执行了之后,让生产者线程等待,而后让消费者线程执行,等待消费者线程执行完成之后就又让生产者线程继续执行。后来我又查了查官方文档,发现Object类中专门有三个方法是与线程相关的:
方法 | 描述 |
---|---|
public final void wait() throws InterruptedException | 线程的等待 |
public final void notify() | 唤醒第一个等待线程 |
public final void notifyAll() |
当我看到这些方法的时候,心里愣了一下,这不就是我们想要的方法吗,用wait()方法来让生产者线程等待,然后运行消费者线程,等消费者线程执行完了之后又让生产者线程去执行。这其中我们用true和false来表示运行开始和运行暂停。
最后我们来看看完成品的代码:
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
|
class TestDemo{ public static void main(String[] args) { Message msg= new Message(); new Thread( new Producer(msg)).start(); new Thread( new Consumer(msg)).start(); } } class Message extends Exception{ private String title,content; private boolean flag= true ; // true表示正在生产,不要来取走,因为没由让消费者区走的 // false表示可以取走,但是不能生产 public synchronized void set(String title,String content){ if ( this .flag== false ){ try { super .wait(); } catch (InterruptedException e){ System.out.println(e); } } this .title=title; try { Thread.sleep( 60 ); } catch (InterruptedException e){ System.out.println(e); } this .content=content; this .flag= true ; // 生产完成,修改标志位 super .notify(); // 唤醒等待线程 } public synchronized void get(){ if (flag== true ) { // 已经生产好了,等待取走 try { super .wait(); } catch (InterruptedException e){ System.out.println(e); } } try { Thread.sleep( 60 ); } catch (InterruptedException e){ System.out.println(e); } System.out.println( this .title+ "-->" + this .content); this .flag= true ; super .notify(); } public String getContent() { return content; } public void setContent(String content) { this .content = content; } public String getTitle() { return title; } public void setTitle(String title) { this .title = title; } } class Producer implements Runnable{ private Message msg= null ; Producer(Message msg){ this .msg=msg; } @Override public void run() { for ( int i= 0 ;i<= 50 ;i++){ if (i% 2 == 0 ){ this .msg.set( "喜欢夜雨吗?" , "是的呢!" ); } else { this .msg.set( "还不关注吗?" , "好的呢!" ); } } } } class Consumer implements Runnable{ private Message msg= null ; Consumer(Message msg){ this .msg=msg; } @Override public void run() { for ( int i= 0 ;i<= 50 ;i++){ this .msg.get(); } } } |
运行结果我就不贴了,你们自己去测试一下吧…
总结
这个案例完美的呈现了线程以及面向对象知识的综合运用,具有很强的实际操作性
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/weixin_43581288/article/details/104784227