(
1
)
Object
的
wait() / notify()
方法 (
2
)
Lock
和
Condition
的
await() / signal()
方法 (
3
)
BlockingQueue
阻塞队列方法 (
4
)
PipedInputStream
/
PipedOutputStream
主类
//
准备数据
Product product
=
new
Product
();
//
准备任务
Producer producer
=
new
Producer
(
product
);
Consumer consumer
=
new
Consumer
(
product
);
//
准备生产线程消费线程
Thread pro
=
new
Thread
(
producer
);
Thread con
=
new
Thread
(
consumer
);
//
开启线程
pro
.
start
();
con
.
start
();
数据类
//
准备生产
public synchronized
void
setProduce
(
String
name
,
double
price
){
if
(
flag
==
true
){
try
{
wait
();//等待
}
catch
(
InterruptedException e
) {
e
.
printStackTrace
();
}
}
this
.
name
=
name
;
this
.
price
=
price
;
System
.
out
.
println
(
Thread
.
currentThread
().
getName
()
+
"
生产
了
:"
+
this
.
name
+
"
价格
:"
+
this
.
price
+
"
数量
:"
+
this
.
number
);
number
++
;
flag
= !
flag
;//控制变量
notify
();唤醒一个其他类
}
//
准备消费
public synchronized
void
getConsume
(){
if
(
flag
==
false
){
try
{
wait
();
}
catch
(
InterruptedException e
) {
e
.
printStackTrace
();
}
}
System
.
out
.
println
(
Thread
.
currentThread
().
getName
()
+
"
消费
了
:"
+
this
.
name
+
"
价格
:"
+
this
.
price
);
flag
= !
flag
;
notify
();
}
//
创建生产任务
class
Producer
implements
Runnable
{
Product product
;
public
Producer
(
Product product
) {
this
.
product
=
product
;
}
@Override
public
void
run
() {
while
(
true
) {
product
.
setProduce
(
"bingbing"
,
10
);
}
}
}
//
创建消费任务
class
Consumer
implements
Runnable
{
Product product
;
public
Consumer
(
Product product
) {
this
.
product
=
product
;
}
@Override
public
void
run
() {
while
(
true
) {
product
.
getConsume
();
}
}
}
多生产者多消费者
错误描述
:
当有两个生产线程
,
两个消费线程同时存在的时候
,
有可能出现生产一次
,
消费
多次或者生产多次消费一次的情况
.
原因
:
当线程被重新唤醒之后
,
没有判断标记
,
直接执行了下面的代码
解决办法
:
将标记处的
if
改成
while
问题描述
:
继续运行程序
,
会出现死锁的情况
(4
个线程同时处于等待状态
)
原因
:
唤醒的是本方的线程
,
最后导致所有的线程都处于等待状态
.
解决办法
:
将
notify
改成
notifyAll.
保证将对方的线程唤醒
//
创建锁对象
Lock lock
=
new
ReentrantLock
();
//
用于生产任务的
Condition
Condition proCon
=
lock
.
newCondition
();
//
用于消费任务的
Condition
Condition conCon
=
lock
.
newCondition
();
比较
synchronized
和
Lock
1.synchronized:
从
jdk1.0
就开始使用的同步方法
-
称为隐式同步
synchronized(
锁对象
){//
获取锁 我们将锁还可以称为锁旗舰或者监听器
同步的代码
}//
释放锁
Lock:
从
jdk1.5
开始使用的同步方法
-
称为显示同步
原理
:Lock
本身是接口
,
要通过他的子类创建对象干活儿
常用子类
:ReentrantLock
使用过程
:
首先调用
lock()
方法获取锁
进行同步的代码块儿
使用
unlock()
方法释放锁
public
void
setProduce
(
String
name
,
double
price
){
try
{
lock
.
lock
();
//
获取锁
while
(
flag
==
true
) {
try
{
//wait();//
让生产线程等待
proCon
.
await
();
}
catch
(
InterruptedException e
) {
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
}
this
.
name
=
name
;
this
.
price
=
price
;
System
.
out
.
println
(
Thread
.
currentThread
().
getName
()
+
"
生产
了
:"
+
this
.
name
+
"
产品的数量
:"
+
this
.
count
+
"
价格
:"
+
this
.
price
);
count
++
;
flag
= !
flag
;
//notify();//
唤醒消费线程
//notifyAll();
conCon
.
signal
();
}
finally
{
lock
.
unlock
();
//
释放锁
}
}
//
准备消费
public
void
getConsume
() {
try
{
lock
.
lock
();
while
(
flag
==
false
) {
try
{
//wait();//
让消费线程等待
conCon
.
await
();
}
catch
(
InterruptedException e
) {
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
}
System
.
out
.
println
(
Thread
.
currentThread
().
getName
()
+
"
消费
了
:"
+
this
.
name
+
"
产品的数量
:"
+
this
.
count
+
"
价格
:"
+
this
.
price
);
//
唤醒生产线程
flag
= !
flag
;
//notify();
//notifyAll();
proCon
.
signal
();
}
finally
{
lock
.
unlock
();
}
}
}
System
.
out
.
println
(
Thread
.
currentThread
().
getName
()
+
"
消费
了
:"
+
this
.
name
+
"
产品的数量
:"
+
this
.
count
+
"
价格
:"
+
this
.
price
);
//
唤醒生产线程
flag
= !
flag
;
//notify();
//notifyAll();
proCon
.
signal
();
}
finally
{
lock
.
unlock
();
}
}
}
//
创建消费任务
class
Consumer2
implements
Runnable
{
Product2 product
;
public
Consumer2
(
Product2 product
) {
super
();
this
.
product
=
product
;
}
public
void
run
() {
while
(
true
) {
product
.
getConsume
();
}
}
}
Object
类中几个方法如下:
wait()
等待,让当前的线程,释放自己持有的指定的锁标记,进入到等待队列。
等待队列中的线程,不参与
CPU
时间⽚的争抢,也不参与锁标记的争抢。
notify()
通知、唤醒。唤醒等待队列中,⼀个等待这个锁标记的随机的线程。
被唤醒的线程,进⼊到锁池,开始争抢锁标记。
notifyAll()
通知、唤醒。唤醒等待队列中,所有的等待这个锁标记的线程。
被唤醒的线程,进⼊到锁池,开始争抢锁标记。
wait
和
sleep
的区别
sleep()
方法,在休眠时间结束后,会自动的被唤醒。 而
wait()
进入到的阻塞态,需要被
notify/notifyAll
手动唤醒。
wait()
会释放自己持有的指定的锁标记,进入到阻塞态。
sleep()
进入到阻塞态的时候,不
会释放自己持有的锁标记。
无论是
wait()
方法,还是
notity()/notifyAll()
⽅法,在使用的时候要注意,⼀定要是自己持
有的锁标记,才可以做这个操作。否则会出现
IllegalMonitorStateException
异常。
Thread vip
=
new
Thread
(()
->
{
for
(
int
i
=
0
;
i
<
50
;
i
++
) {
System
.
out
.
println
(
"
窗口卖出一张票给
VIP
团队,剩余
: "
+
--
ticketCount
);
}
});
//
先开启
vip
.
start
();
//
再合并
try
{
vip
.
join
();
}
catch
(
InterruptedException e
) {
e
.
printStackTrace
();
}
}
//
设置线程的优先级, 必须在这个线程启动之前
thread0
.
setPriority
(
1
);
thread1
.
setPriority
(
10
);