Object.wait:释放锁,当时代码不会往下继续执行,需要等待notify通知,wait(1000)超过1秒自动唤醒
Object.notify:不释放锁,需要等到同步代码块执行完毕,如果没有wait线程,notify命令将被忽略。
condition
如果有多个线程处于等待状态,我想唤醒指定的一个线程,Object.notify是唤醒随机一个是无法实现的。condition实现过程如下:
ReentrantLock lock = new ReentrantLock(true);
Condition aCondition = reentrantLock.newCondition();
Condition cCondition = reentrantLock.newCondition();
//线程A:
{
lock.lock();
aCondition.await(); //此时当前线程释放lock锁,进入[等待状态],等待其他线程执行aCondition.signal()时才有可能执行
A do something
lock.unlock();
}
//线程C:
{
lock.lock();
cCondition.await();
do something
lock.unlock();
}
//线程B:
{
lock.lock();
aCondition.signal(); //此时当前线程释放lock锁,随机唤醒一个处于等待状态等待aCondition的线程,继续执行await后面的程序。
//cCondition.signal(); ////此时当前线程释放lock锁,随机唤醒一个处于等待状态等待cCondition的线程,继续执行await后面的程序。
lock.unlock();
}
condition在唤醒的时候可以指定唤醒哪个锁下的线程。
【使用线程间的通信实现生产者消费者】
【生产者】
package com.fyw.thread;
public class Producer {
private String lock;
public Producer(String lock) {
super();
this.lock = lock;
}
public void produce(){
try {
synchronized (lock) {
if(!ValueObject.value.equals("")){
lock.wait();
}
ValueObject.value = String.valueOf(System.currentTimeMillis())+System.nanoTime();
System.out.println("生产:"+ValueObject.value);
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.fyw.thread;
public class ThreadProduce extends Thread {
private Producer p ;
public ThreadProduce(Producer p) {
super();
this.p = p;
}
@Override
public void run() {
for(;;){
p.produce();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
【消费者】
package com.fyw.thread;
public class Consumer {
private String lock;
public Consumer(String lock) {
super();
this.lock = lock;
}
public void consume(){
try {
synchronized (lock) {
if(ValueObject.value.equals("")){
lock.wait();
}
System.out.println("消费:"+ValueObject.value);
// 消费
ValueObject.value="";
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.fyw.thread;
public class ThreadConsumer extends Thread {
private Consumer c;
public ThreadConsumer(Consumer c) {
super();
this.c = c;
}
@Override
public void run() {
for(;;){
c.consume();
}
}
}
【启动】
package com.fyw.thread;
public class PCTest {
public static void main(String[] args) {
String lock = new String("lock");
Producer p = new Producer(lock);
Consumer c = new Consumer(lock);
ThreadProduce tp = new ThreadProduce(p);
ThreadConsumer tc = new ThreadConsumer(c);
tp.start();
tc.start();
}
}
【输出】
生产:154462818466096495898923525
消费:154462818466096495898923525
生产:154462818566096496899278715
消费:154462818566096496899278715
生产:154462818666196497899629894
消费:154462818666196497899629894
生产:154462818766196498900164868
消费:154462818766196498900164868
生产:154462818866296499901082747
消费:154462818866296499901082747
生产:154462818966396500901689196
消费:154462818966396500901689196
生产:154462819066396501901767236
消费:154462819066396501901767236
生产:154462819166396502901990051
消费:154462819166396502901990051
生产:154462819266396503902137378
消费:154462819266396503902137378
【实现长度为1的阻塞队列】
【出队列与入队列】
package com.fyw.thread.queue;
import java.util.ArrayList;
import java.util.List;
public class MyBlockQueue {
private List<String> list = new ArrayList<>();
synchronized public void push(){
try {
if(this.list.size() == 1){
this.wait();
}
list.add("object"+Math.random());
this.notify();
System.out.println("push list size is "+list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public String pop(){
String popValue = "";
try {
if(this.list.size() == 0){
this.wait();
}
popValue = " "+list.get(0);
System.out.println("the popValue is:"+popValue);
list.remove(0);
this.notify();
System.out.println("pop list size is "+list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
return popValue;
}
}
【循环入队】
package com.fyw.thread.queue;
public class PushThread extends Thread {
private MyBlockQueue stack;
public PushThread(MyBlockQueue stack) {
super();
this.stack = stack;
}
@Override
public void run() {
for(;;){
stack.push();
}
}
}
【循环出队】
package com.fyw.thread.queue;
public class PopThread extends Thread {
private MyBlockQueue stack;
public PopThread(MyBlockQueue stack) {
super();
this.stack = stack;
}
@Override
public void run() {
for(;;){
stack.pop();
}
}
}
【测试】
package com.fyw.thread.queue;
public class TestQueue {
public static void main(String[] args) {
MyBlockQueue stack = new MyBlockQueue();
PushThread push = new PushThread(stack);
PopThread pop = new PopThread(stack);
push.start();
pop.start();
}
}
【输出】
push list size is 1
the popValue is: object0.6381141020856054
pop list size is 0
push list size is 1
the popValue is: object0.7736294633434665
pop list size is 0
push list size is 1
the popValue is: object0.2567516689810333
pop list size is 0
push list size is 1
the popValue is: object0.024418178034380067
pop list size is 0
push list size is 1
the popValue is: object0.6143726198167988
pop list size is 0
push list size is 1
the popValue is: object0.49025399739088094
pop list size is 0
push list size is 1
the popValue is: object0.8784830759986317
pop list size is 0
上面的是1对1的生产者消费者模型,如果是1对多或者多对多,list.size需要使用while判断,否则当其他线程修改size值对当前线程无感知,导致条件判断错误,然后notify改成notifyAll防止出现线程假死状态。
【使用wait和notify实现交叉执行示例】
package com.fyw.thread.queue;
public class DBTools {
private volatile boolean isTurn = false;
synchronized public void bakupA(){
try {
while(this.isTurn){
this.wait();
}
for(int i=0;i<5;i++){
System.out.println("AAAAAA");
}
this.isTurn = true;
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void bakupB(){
try {
while(!this.isTurn){
this.wait();
}
for(int i=0;i<5;i++){
System.out.println("BBBBBB");
}
this.isTurn = false;
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.fyw.thread.queue;
public class PopThread extends Thread {
private DBTools db;
public PopThread(DBTools db) {
super();
this.db = db;
}
@Override
public void run() {
db.bakupA();
}
}
package com.fyw.thread.queue;
public class PushThread extends Thread {
private DBTools db;
public PushThread(DBTools db) {
super();
this.db = db;
}
@Override
public void run() {
db.bakupB();
}
}
package com.fyw.thread.queue;
public class TestQueue {
public static void main(String[] args) {
DBTools stack = new DBTools();
for(int i=0;i<20;i++){
PushThread push = new PushThread(stack);
push.start();
PopThread pop = new PopThread(stack);
pop.start();
}
}
}
【运行结果如下】
AAAAAA
AAAAAA
AAAAAA
AAAAAA
AAAAAA
BBBBBB
BBBBBB
BBBBBB
BBBBBB
BBBBBB
AAAAAA
AAAAAA
AAAAAA
AAAAAA
AAAAAA
BBBBBB
BBBBBB
BBBBBB
BBBBBB
BBBBBB
AAAAAA
AAAAAA
AAAAAA
AAAAAA
AAAAAA
BBBBBB
BBBBBB
BBBBBB
BBBBBB
BBBBBB