工具版本兼容问题
线程之间有交互通知 的需求,考虑如下情况:
有两个线程,处理同一个英雄。
一个加血,一个减血。
减血的线程,发现血量=1,就停止减血,直到加血的线程为英雄加了血,才可以继续减血
纠
本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
16分9秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。
如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。
chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器
播放本视频会花费
3 个积分,您目前总共有
点积分。再次播放不会花费额外积分
积分增加办法
或者
一次性购买 总计
73个视频
步骤
1
:
不好的解决方式
步骤
2
:
使用wait和notify进行线程交互
步骤
3
:
关于wait、notify和notifyAll
步骤
4
:
练习-线程交互
步骤
5
:
答案-线程交互
步骤
6
:
练习-多线程交互
步骤
7
:
答案-多线程交互
步骤
8
:
练习-生产者消费者问题
步骤
9
:
答案-生产者消费者问题
故意设计减血线程频率更高,盖伦的血量迟早会到达1 减血线程中使用while循环判断是否是1 ,如果是1就不停的循环,直到加血线程回复了血量 这是不好的解决方式,因为会大量占用CPU,拖慢性能
代码比较
复制代码
package charactor;
public class Hero{
public String name;
public float hp;
public int damage;
public synchronized void recover(){
hp=hp+1;
}
public synchronized void hurt(){
hp=hp-1;
}
public void attackHero(Hero h) {
h.hp-=damage;
System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n",name,h.name,h.name,h.hp);
if(h.isDead())
System.out.println(h.name +"死了!");
}
public boolean isDead() {
return 0>=hp?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
package
charactor;
public
class
Hero{
public
String name;
public
float
hp;
public
int
damage;
public
synchronized
void
recover(){
hp=hp+
1
;
}
public
synchronized
void
hurt(){
hp=hp-
1
;
}
public
void
attackHero(Hero h) {
h.hp-=damage;
System.out.format(
"%s 正在攻击 %s, %s的血变成了 %.0f%n"
,name,h.name,h.name,h.hp);
if
(h.isDead())
System.out.println(h.name +
"死了!"
);
}
public
boolean
isDead() {
return
0
>=hp?
true
:
false
;
}
}
代码比较
复制代码
package multiplethread;
import java.awt.GradientPaint;
import charactor.Hero;
public class TestThread {
public static void main(String[] args) {
final Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
Thread t1 = new Thread(){
public void run(){
while(true){
//因为减血更快,所以盖伦的血量迟早会到达1
//使用while循环判断是否是1,如果是1就不停的循环
//直到加血线程回复了血量
while(gareen.hp==1){
continue;
}
gareen.hurt();
System.out.printf("t1 为%s 减血1点,减少血后,%s的血量是%.0f%n",gareen.name,gareen.name,gareen.hp);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
public void run(){
while(true){
gareen.recover();
System.out.printf("t2 为%s 回血1点,增加血后,%s的血量是%.0f%n",gareen.name,gareen.name,gareen.hp);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t2.start();
}
}
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
package
multiplethread;
import
java.awt.GradientPaint;
import
charactor.Hero;
public
class
TestThread {
public
static
void
main(String[] args) {
final
Hero gareen =
new
Hero();
gareen.name =
"盖伦"
;
gareen.hp =
616
;
Thread t1 =
new
Thread(){
public
void
run(){
while
(
true
){
while
(gareen.hp==
1
){
continue
;
}
gareen.hurt();
System.out.printf(
"t1 为%s 减血1点,减少血后,%s的血量是%.0f%n"
,gareen.name,gareen.name,gareen.hp);
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 =
new
Thread(){
public
void
run(){
while
(
true
){
gareen.recover();
System.out.printf(
"t2 为%s 回血1点,增加血后,%s的血量是%.0f%n"
,gareen.name,gareen.name,gareen.hp);
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t2.start();
}
}
步骤
2
:
使用wait和notify进行线程交互
edit
顶
折
在Hero类中:hurt()减血方法:当hp=1的时候,执行this.wait(). this.wait()表示 让占有this的线程等待,并临时释放占有 进入hurt方法的线程必然是减血线程,this.wait()会让减血线程临时释放对this的占有。 这样加血线程,就有机会进入recover()加血方法了 。 recover() 加血方法:增加了血量,执行this.notify(); this.notify() 表示通知那些等待在this的线程 ,可以苏醒过来了。 等待在this的线程,恰恰就是减血线程。 一旦recover()结束, 加血线程释放了this,减血线程,就可以重新占有this,并执行后面的减血工作。
代码比较
复制代码
package charactor;
public class Hero {
public String name;
public float hp;
public int damage;
public synchronized void recover() {
hp = hp + 1;
System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp);
// 通知那些等待在this对象上的线程,可以醒过来了,如第20行,等待着的减血线程,苏醒过来
this.notify();
}
public synchronized void hurt() {
if (hp == 1) {
try {
// 让占有this的减血线程,暂时释放对this的占有,并等待
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
hp = hp - 1;
System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp);
}
public void attackHero(Hero h) {
h.hp -= damage;
System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp);
if (h.isDead())
System.out.println(h.name + "死了!");
}
public boolean isDead() {
return 0 >= hp ? 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
package
charactor;
public
class
Hero {
public
String name;
public
float
hp;
public
int
damage;
public
synchronized
void
recover() {
hp = hp +
1
;
System.out.printf(
"%s 回血1点,增加血后,%s的血量是%.0f%n"
, name, name, hp);
this
.notify();
}
public
synchronized
void
hurt() {
if
(hp ==
1
) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
hp = hp -
1
;
System.out.printf(
"%s 减血1点,减少血后,%s的血量是%.0f%n"
, name, name, hp);
}
public
void
attackHero(Hero h) {
h.hp -= damage;
System.out.format(
"%s 正在攻击 %s, %s的血变成了 %.0f%n"
, name, h.name, h.name, h.hp);
if
(h.isDead())
System.out.println(h.name +
"死了!"
);
}
public
boolean
isDead() {
return
0
>= hp ?
true
:
false
;
}
}
代码比较
复制代码
package multiplethread;
import java.awt.GradientPaint;
import charactor.Hero;
public class TestThread {
public static void main(String[] args) {
final Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
Thread t1 = new Thread(){
public void run(){
while(true){
//无需循环判断
// while(gareen.hp==1){
// continue;
// }
gareen.hurt();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
public void run(){
while(true){
gareen.recover();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t2.start();
}
}
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
package
multiplethread;
import
java.awt.GradientPaint;
import
charactor.Hero;
public
class
TestThread {
public
static
void
main(String[] args) {
final
Hero gareen =
new
Hero();
gareen.name =
"盖伦"
;
gareen.hp =
616
;
Thread t1 =
new
Thread(){
public
void
run(){
while
(
true
){
gareen.hurt();
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 =
new
Thread(){
public
void
run(){
while
(
true
){
gareen.recover();
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t2.start();
}
}
步骤
3
:
关于wait、notify和notifyAll
edit
顶
折
留意wait()和notify() 这两个方法是什么对象上的?
public synchronized void hurt() {
。。。
this.wait();
。。。
}
public synchronized void recover() {
。。。
this.notify();
}
这里需要强调的是,wait方法和notify方法,并
不是Thread线程上的方法 ,它们是Object上的方法。
因为所有的Object都可以被用来作为同步对象,所以准确的讲,wait和notify是同步对象上的方法。
wait()的意思是: 让占用了这个同步对象的
线程 ,临时释放当前的占用,并且等待。 所以调用wait是有前提条件的,一定是在synchronized块里,否则就会出错。
notify() 的意思是,通知
一个 等待在这个同步对象上的线程,
你 可以苏醒过来了,有机会重新占用当前对象了。
notifyAll() 的意思是,通知
所有的 等待在这个同步对象上的线程,
你们 可以苏醒过来了,有机会重新占用当前对象了。
假设加血线程运行得更加频繁,英雄的最大血量是1000 设计加血线程和减血线程的交互,让回血回满之后,加血线程等待,直到有减血线程减血
查看答案
请先登录
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 ( 已经购买,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 (已经看过,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案(消耗积分)
查看本答案会花费4 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
积分不足
查看本答案会花费4 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
3分11秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。
如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。
chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器
代码比较
复制代码
package charactor;
public class Hero {
public String name;
public float hp;
public int damage;
public synchronized void recover() {
//当血量大于或者等于1000的时候
//this.wait() 让占用这个对象的线程等待,并临时释放锁
if(hp>=1000){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
hp = hp + 1;
System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp);
this.notify();
}
public synchronized void hurt() {
if (hp == 1) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
hp = hp - 1;
System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp);
//掉血之后,唤醒等待的线程
this.notify();
}
public void attackHero(Hero h) {
h.hp -= damage;
System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp);
if (h.isDead())
System.out.println(h.name + "死了!");
}
public boolean isDead() {
return 0 >= hp ? 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
package
charactor;
public
class
Hero {
public
String name;
public
float
hp;
public
int
damage;
public
synchronized
void
recover() {
if
(hp>=
1000
){
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
hp = hp +
1
;
System.out.printf(
"%s 回血1点,增加血后,%s的血量是%.0f%n"
, name, name, hp);
this
.notify();
}
public
synchronized
void
hurt() {
if
(hp ==
1
) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
hp = hp -
1
;
System.out.printf(
"%s 减血1点,减少血后,%s的血量是%.0f%n"
, name, name, hp);
this
.notify();
}
public
void
attackHero(Hero h) {
h.hp -= damage;
System.out.format(
"%s 正在攻击 %s, %s的血变成了 %.0f%n"
, name, h.name, h.name, h.hp);
if
(h.isDead())
System.out.println(h.name +
"死了!"
);
}
public
boolean
isDead() {
return
0
>= hp ?
true
:
false
;
}
}
代码比较
复制代码
package multiplethread;
import charactor.Hero;
public class TestThread {
public static void main(String[] args) {
final Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
Thread t1 = new Thread(){
public void run(){
while(true){
gareen.hurt();
try {
//减慢掉血的速度
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
public void run(){
while(true){
gareen.recover();
try {
//加快回血的速度
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t2.start();
}
}
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
package
multiplethread;
import
charactor.Hero;
public
class
TestThread {
public
static
void
main(String[] args) {
final
Hero gareen =
new
Hero();
gareen.name =
"盖伦"
;
gareen.hp =
616
;
Thread t1 =
new
Thread(){
public
void
run(){
while
(
true
){
gareen.hurt();
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 =
new
Thread(){
public
void
run(){
while
(
true
){
gareen.recover();
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t2.start();
}
}
在上面的练习的基础上,增加回血线程到2条,减血线程到5条,同时运行。 运行一段时间,观察会发生的错误,分析错误原因,并考虑解决办法
查看答案
请先登录
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 ( 已经购买,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 (已经看过,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案(消耗积分)
查看本答案会花费4 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
积分不足
查看本答案会花费4 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
9分55秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。
如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。
chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器
在目前的状态下,会导致英雄的血量变为负数。 这是因为减血线程调用hurt() 方法结束时,调用notify,有可能会唤醒另一个减血线程,这就导致不停的减血。
解决办法是: 减血线程被唤醒后,要再次查看当前血量,如果当前血量<=1,那么就继续等待
//把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行
//把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行
//if(hp <= 1) {
while (hp <= 1) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
代码比较
复制代码
package charactor;
public class Hero {
public String name;
public float hp;
public int damage;
public synchronized void recover() {
//当血量大于或者等于1000的时候
//this.wait() 让占用这个对象的线程等待,并临时释放锁
while(hp>=1000){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
hp = hp + 1;
System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp);
this.notify();
}
public synchronized void hurt() {
//把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行
//if (hp <= 1) {
while (hp <= 1) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
hp = hp - 1;
System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp);
//掉血之后,唤醒等待的线程
this.notify();
}
public void attackHero(Hero h) {
h.hp -= damage;
System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp);
if (h.isDead())
System.out.println(h.name + "死了!");
}
public boolean isDead() {
return 0 >= hp ? 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
package
charactor;
public
class
Hero {
public
String name;
public
float
hp;
public
int
damage;
public
synchronized
void
recover() {
while
(hp>=
1000
){
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
hp = hp +
1
;
System.out.printf(
"%s 回血1点,增加血后,%s的血量是%.0f%n"
, name, name, hp);
this
.notify();
}
public
synchronized
void
hurt() {
while
(hp <=
1
) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
hp = hp -
1
;
System.out.printf(
"%s 减血1点,减少血后,%s的血量是%.0f%n"
, name, name, hp);
this
.notify();
}
public
void
attackHero(Hero h) {
h.hp -= damage;
System.out.format(
"%s 正在攻击 %s, %s的血变成了 %.0f%n"
, name, h.name, h.name, h.hp);
if
(h.isDead())
System.out.println(h.name +
"死了!"
);
}
public
boolean
isDead() {
return
0
>= hp ?
true
:
false
;
}
}
代码比较
复制代码
package multiplethread;
import charactor.Hero;
public class TestThread {
static class HurtThread extends Thread{
private Hero hero;
public HurtThread(Hero hero){
this.hero = hero;
}
public void run(){
while(true){
hero.hurt();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
static class RecoverThread extends Thread{
private Hero hero;
public RecoverThread(Hero hero){
this.hero = hero;
}
public void run(){
while(true){
hero.recover();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
for (int i = 0; i < 2; i++) {
new RecoverThread(gareen).start();
}
for (int i = 0; i < 5; i++) {
new HurtThread(gareen).start();
}
}
}
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
package
multiplethread;
import
charactor.Hero;
public
class
TestThread {
static
class
HurtThread
extends
Thread{
private
Hero hero;
public
HurtThread(Hero hero){
this
.hero = hero;
}
public
void
run(){
while
(
true
){
hero.hurt();
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
static
class
RecoverThread
extends
Thread{
private
Hero hero;
public
RecoverThread(Hero hero){
this
.hero = hero;
}
public
void
run(){
while
(
true
){
hero.recover();
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
public
static
void
main(String[] args) {
final
Hero gareen =
new
Hero();
gareen.name =
"盖伦"
;
gareen.hp =
616
;
for
(
int
i =
0
; i <
2
; i++) {
new
RecoverThread(gareen).start();
}
for
(
int
i =
0
; i <
5
; i++) {
new
HurtThread(gareen).start();
}
}
}
生产者消费者问题是一个非常典型性的线程交互的问题。
1. 使用
栈 来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。 当栈里的数据是200的时候,访问push的线程就会等待
2. 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
3. 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
4. 提供一个测试类,使两个生产者和三个消费者线程同时运行,结果类似如下 :
查看答案
请先登录
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 ( 已经购买,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案 (已经看过,不耗积分)
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看答案(消耗积分)
查看本答案会花费5 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
积分不足
查看本答案会花费5 个积分,您目前总共有 点积分。查看相同答案不会花费额外积分。
积分增加办法
或者一次性购买 JAVA 中级总计0个答案
(总共需要0积分)
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
8分54秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。
如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。
chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器
代码比较
复制代码
package multiplethread;
import java.util.ArrayList;
import java.util.LinkedList;
public class MyStack<T> {
LinkedList<T> values = new LinkedList<T>();
public synchronized void push(T t) {
while(values.size()>=200){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notifyAll();
values.addLast(t);
}
public synchronized T pull() {
while(values.isEmpty()){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notifyAll();
return values.removeLast();
}
public T peek() {
return values.getLast();
}
}
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
package multiplethread;
import java.util.ArrayList;
import java.util.LinkedList;
public class MyStack<
T
> {
LinkedList<
T
> values = new LinkedList<
T
>();
public synchronized void push(T t) {
while(values.size()>=200){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notifyAll();
values.addLast(t);
}
public synchronized T pull() {
while(values.isEmpty()){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notifyAll();
return values.removeLast();
}
public T peek() {
return values.getLast();
}
}
代码比较
复制代码
package multiplethread;
public class ProducerThread extends Thread{
private MyStack<Character> stack;
public ProducerThread(MyStack<Character> stack,String name){
super(name);
this.stack =stack;
}
public void run(){
while(true){
char c = randomChar();
System.out.println(this.getName()+" 压入: " + c);
stack.push(c);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public char randomChar(){
return (char) (Math.random()*('Z'+1-'A') + 'A');
}
}
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
package multiplethread;
public class ProducerThread extends Thread{
private MyStack<
Character
> stack;
public ProducerThread(MyStack<
Character
> stack,String name){
super(name);
this.stack =stack;
}
public void run(){
while(true){
char c = randomChar();
System.out.println(this.getName()+" 压入: " + c);
stack.push(c);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public char randomChar(){
return (char) (Math.random()*('Z'+1-'A') + 'A');
}
}
代码比较
复制代码
package multiplethread;
public class ConsumerThread extends Thread{
private MyStack<Character> stack;
public ConsumerThread(MyStack<Character> stack,String name){
super(name);
this.stack =stack;
}
public void run(){
while(true){
char c = stack.pull();
System.out.println(this.getName()+" 弹出: " + c);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public char randomChar(){
return (char) (Math.random()*('Z'+1-'A') + 'A');
}
}
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
package multiplethread;
public class ConsumerThread extends Thread{
private MyStack<
Character
> stack;
public ConsumerThread(MyStack<
Character
> stack,String name){
super(name);
this.stack =stack;
}
public void run(){
while(true){
char c = stack.pull();
System.out.println(this.getName()+" 弹出: " + c);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public char randomChar(){
return (char) (Math.random()*('Z'+1-'A') + 'A');
}
}
代码比较
复制代码
package multiplethread;
public class TestThread {
public static void main(String[] args) {
MyStack<Character> stack = new MyStack<>();
new ProducerThread(stack, "Producer1").start();
new ProducerThread(stack, "Producer2").start();
new ConsumerThread(stack, "Consumer1").start();
new ConsumerThread(stack, "Consumer2").start();
new ConsumerThread(stack, "Consumer3").start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package multiplethread;
public class TestThread {
public static void main(String[] args) {
MyStack<
Character
> stack = new MyStack<>();
new ProducerThread(stack, "Producer1").start();
new ProducerThread(stack, "Producer2").start();
new ConsumerThread(stack, "Consumer1").start();
new ConsumerThread(stack, "Consumer2").start();
new ConsumerThread(stack, "Consumer3").start();
}
}
代码高亮插件双击即可选中,不过部分同学反应,通过代码高亮插件复制的代码无法在IDEA里正常显示,这里提供TEXTAREA的方式,方便复制,谢谢
分享如下连接可增加积分,获取50% 佣金
推
如果不方便发连接(如贴吧),可以使用如下由连接转换为的二维码. 鼠标在图片上右键,然后另存为即可
警告: 请勿使用挂机软件刷积分,刷积分不会导致任何注册量,很容易被识别。 一旦发现刷积分,即封号处理,请勿做吃力不讨好之事。
1. 自行完成练习
根据练习目标尽量自己实现代码效果,期间会碰到疑问,难题,和自己不懂的地方,这些都是必要的过程
2. 带着疑问查看答案
完成过程中,碰到无法解决的问题,带着疑问,查看答案,分析答案的解决思路
3. 查看答案讲解视频
依然有不明白的地方,点开视频讲解,带着疑问,听视频讲解有问题的部分
4. 再做一遍
理解后,再从头做一遍,把有疑问的地方都捋清楚
5. 总结
最后再总结一遍,总结思路,总结解决办法,以后遇到类似的问题,怎么处理
有的同学收藏是为了进行标记,过段时间再来看不明白的地方,在此处可以记录哪里不明白. 单纯收藏的, 直接点击提交即可。
站长比较马虎,难免出现错别字,如果发现哪里文字有误,请提交错误,站长会尽快修改,谢谢
HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。
提问太多,页面渲染太慢,为了加快渲染速度,本页最多只显示几条提问。还有 82 条以前的提问,请 点击查看