【
线程间的通讯
wait()在对象上等待,等待通知(在等待过程中释放对象锁、等待必须在同步块内、这个对象就是同步锁)《让线程进入阻塞状态,将线程放入等待池中》
notify()通知在这个对象上等待的一个线程,唤醒它,让它不再等下去(必须在同步块内调用,同步锁必须是调用这个方法的对象)《》
notifyAll()和notify()差不多,区别在于是通知在这个对象上等待的所有线程
注意:线程间通讯的几个方法()
总结:wait、notify、notifyAll必须是同步代码块中被调用,
】
wait()在对象上等待,等待通知(在等待过程中释放对象锁、等待必须在同步块内、这个对象就是同步锁)
【
//要在这个线程中等待
public class Wifeextends Thread {
private Object message;//等待对象,同时也是同步锁
public Wife(Object message) {
this.message = message; //初始化,从外部传入
}
public void run(){
synchronized (message){//wait动作必须在一个同步块内部,而且对象锁必须是等待的对象
System.out.println("开始等待");
try {
message.wait();//在对象进行等待,等待过程中释放锁,另一线程的同步块得以执行
System.out.println("收到音讯,结束等待");
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
public class Husband{
public static void main(String[] args){
Object message = new Object(); //创建对象
Wife t = newWife(message); //新建线程,传入对象
t.start();//启动
System.out.println("上京赶考");
try {
Thread.sleep(5000);
} catch (InterruptedExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
System.out.println("考上状元");
System.out.println("飞鸽传书");
synchronized (message){//notify动作必须在同步块内,而且对象锁必须是调用通知的对象
message.notify();//通知在这个对象上等待的线程,当这个同步块结束,通知的那个线程的wait就返回并继续执行
}
}
}
】
notify()通知在这个对象上等待的一个线程,唤醒它,让它不再等下去(必须在同步块内调用,同步锁必须是调用这个方法的对象)
notifyAll()和notify()差不多,区别在于是通知在这个对象上等待的所有线程
【
public class CowManextends Thread {
private Object message;
public CowMan(Object message) {
this.message = message;
}
public void run(){
synchronized (message) {
System.out.println("牛郎等待");
try {
message.wait();
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
System.out.println("牛郎去鹊桥");
}
}
}
public class Fairyextends Thread {
private Object message;
public Fairy(Object message) {
this.message = message;
}
public void run(){
synchronized (message) {
System.out.println("织女等待");
try {
message.wait();
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
System.out.println("兴冲冲跑去鹊桥相会");
}
}
}
public static voidmain(String[] args) throws Exception {
Object message = newObject();//创建共同使用的信息对象
CowMan cowMan = newCowMan(message);//牛郎和织女都等待同一个信息,七月初七到来的信息
Fairy fairy = newFairy(message);
cowMan.start();
fairy.start();
for(int i=1;i<=7;i++){
System.out.println("七月初"+i);
Thread.sleep(1000);
}
synchronized (message) {
message.notifyAll();//通知在这个对象上等待着的所有线程,牛郎和织女
}
}
】
1.1 生产者消费者模式
【
public class Demo {
publicstatic void main(String[] args) {
Resouser = new Resouse("苹果");
newProduce("生产者", r).start();
newConsumer("消费者", r).start();
}
}
/**
* 消费者类
*
*/
class Consumer extends Thread {
Resouser;
publicConsumer(String name, Resouse r) {
super(name);
this.r= r;
}
@Override
publicvoid run() {
//不停拿资源
while(true) {
r.get();
}
}
}
class Produce extends Thread {
Resouser;
publicProduce(String name, Resouse r) {
super(name);
this.r= r;
}
@Override
publicvoid run() {
//不停生产
while(true) {
r.put();
}
}
}
class Resouse {
Stringname;
intid;
booleanflag; // 记录有没有资源
publicResouse(String name) {
this.name= name;
}
/**
* 放资源
*/
publicsynchronized void put() {
try{
if(flag) {
wait();//让线程进入等待状态(阻塞状态的一种),直到被notify()方法唤醒
}
//生产资源
id++;
System.out.println(Thread.currentThread().getName()+ "...生产了....."
+name + id);
flag= true;
//通知消费者
notify();
Thread.sleep(500);
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
//【同步方法的实质是同步代码块,同一个类中的不同行为<方法>的同步,是可行的。同步锁是当前对象,
//即在多线程中同一时间片段中,对象只会调用类中同步的其中一个同步方法】
/**
* 取资源
*/
public/*synchronized */void get() {
synchronized(this) {//同步锁就是对象监视器,他只会监控同步锁对应的代码块中的代码
try{
if(!flag) { // 没有资源就等待生产
wait();
}
System.out.println(Thread.currentThread().getName()
+"...消费了...." + name + id);
flag= false; // 消费完得告诉生产者没有资源了
//通知生产者
notify();
Thread.sleep(500);
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
】
1.2 生产者消费者复合模式
【
publicclass Demo {
public static void main(String[] args){
Resouse r = newResouse("苹果");
new Produce("生产者1号",r).start();
new Consumer("消费者1号",r).start();
new Produce("生产者2号", r).start();
new Consumer("消费者2号",r).start();
new Produce("生产者3号",r).start();
}
}
/**
* 消费者类
*
*/
classConsumer extends Thread {
Resouse r;
public Consumer(String name, Resouse r){
super(name);
this.r = r;
}
@Override
public void run() {
// 不停拿资源
while (true) {
r.get();
}
}
}
classProduce extends Thread {
Resouse r;
public Produce(String name, Resouse r){
super(name);
this.r = r;
}
@Override
public void run() {
// 不停生产
while (true) {
r.put();
}
}
}
classResouse {
String name;
int id;
boolean flag; // 记录有没有资源
public Resouse(String name) {
this.name = name;
}
/**
* 放资源
*/
public synchronized void put() {
try {
while (flag) {
wait();// 让线程进入等待状态(阻塞状态的一种),直到被notify()方法唤醒
}
// 生产资源
id++;
System.out.println(Thread.currentThread().getName()+ "...生产了....."
+name + id);
flag = true;
// 通知消费者
notifyAll();
Thread.sleep(500);
} catch (InterruptedExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
// 【同步方法的实质是同步代码块,同一个类中的不同行为<方法>的同步,是可行的。同步锁是当前对象,
// 即在多线程中同一时间片段中,对象只会调用类中同步的其中一个同步方法】
/**
* 取资源
*/
public/* synchronized */void get() {
synchronized (this) {//同步锁就是对象监视器,他只会监控同步锁对应的代码块中的代码
try {
while(!flag) { // 没有资源就等待生产
wait();
}
System.out.println(Thread.currentThread().getName()
+"...消费了...."+ name + id);
flag =false; // 消费完得告诉生产者没有资源了
// 通知生产者
notifyAll();
Thread.sleep(500);
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
】
1.3 新的线程同步方法
【
多生产者多消费者的问题
1、 if语句换成while语句
可以保证在生产或消费之前都先判断一次资源的情况
2、 notity方法换成notifyAll方法
可以保证每次都能唤醒对方的线程
在JDK1.5之后,可以使用Lock接口和Condition接口来解决以上问题
1.3.1 Lock接口
通过Lock接口也可以实现线程的同步处理,并且可以让同步处理变得更加灵活(需要手动实现获取锁和释放锁的操作)
//示例代码
//创建Lock对象(可以将Lock对象理解为原来的锁对象)
Locklock = new ReentrantLock();
lock.lock();//获取锁
try{
//被同步的代码
}finally {
lock.unlock();//释放锁
}
1.3.2 Condition接口
Condition对象将原先在Object类中的监视器方法(wait、notify、notifyAll)抽取出来进行封装,每一个Condition对象都是一个等待池,一个Lock对象可以绑定多个Condition对象,这样一来可以让线程间的通讯操作变得更加灵活。
//创建Condition对象,并和指定的Lock对象绑定
Lock lock = ...;
Condition condition = lock.newCondition();
线程间通讯的三个方法
1)await():替代wait方法
2)signal():替代notify方法
3)signalAll():替代notifyAll方法
】
1.3.3 示例1
【
/*
* 有5辆火车要过山洞,但确保山洞同时只能有一辆火车通过(过山洞需要1秒),打印输出火车通过的顺序。
* (过山洞的顺序是不可控的,只要保证同一时间只有一辆火车能通过山洞即可)
* 提示:使用线程同步,一辆火车就是一个线程
*/
publicclass LockDemo {
public static void main(String[] args){
// TODO Auto-generated methodstub
newTrain("火车1").start();
new Train("火车2").start();
new Train("火车3").start();
new Train("火车4").start();
new Train("火车5").start();
}
}
classTrain extends Thread{
//创建Lock对象
static Lock lock = new ReentrantLock();
public Train(String name){
super(name);
}
@Override
public void run() {
//获取锁
lock.lock();
try {
System.out.println(getName()+"过山洞.....");
Thread.sleep(1000);
} catch (InterruptedExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}finally{
//释放锁
lock.unlock();
}
}
}
】
1.3.4 新线程同步复合应用
【
publicclass Demo {
public static void main(String[] args){
// TODO Auto-generated methodstub
Resource r = newResource("苹果");
new Producer("生产者1号",r).start();
new Producer("生产者2号",r).start();
new Consumer("消费者1号",r).start();
new Consumer("消费者2号",r).start();
new Consumer("消费者三号", r).start();
}
}
/*
* 消费者类
*/
classConsumer extends Thread {
Resource r;
public Consumer(String name, Resourcer) {
super(name);
this.r = r;
}
@Override
public void run() {
while (true) {
r.get();
}
}
}
/*
* 生产者类
*/
classProducer extends Thread {
Resource r;
public Producer(String name, Resourcer) {
super(name);
this.r = r;
}
@Override
public void run() {
while (true) {
r.put();
}
}
}
/*
* 资源类
*/
classResource {
String name;
int id;
boolean flag; // 记录有没有资源
// Lock对象,用于替代同步代码块
Lock lock = new ReentrantLock();
// 创建两个等待池
// 生产者线程用的等待池
Condition producerCon =lock.newCondition();
// 消费者线程用的等待池
Condition consumCon =lock.newCondition();
public Resource(String name) {
this.name = name;
}
// 放资源
public void put() {
lock.lock();
try {
while (flag) {
// 将当前线程(生产者线程放入等待池)
producerCon.await();// 替代了wait方法
}
// 生产资源
id++;
System.out.println(Thread.currentThread().getName()+ "...生产了...."
+name + id);
flag = true;
// 通知消费者消费
// 唤醒消费者等待池中的线程
consumCon.signal();
Thread.sleep(500);
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get() {
lock.lock();
try {
while (!flag) {
consumCon.await();
}
// 消费资源
System.out.println(Thread.currentThread().getName()+ "....消费了...."
+name + id);
flag = false;
//通知生产者生产
producerCon.signal();
Thread.sleep(500);
} catch (InterruptedExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
】