多线程(线程间通信问题)

代码1线程不安全:

/**
* 线程间通信
* 其实就是多线程在操作同一个资源
* 但是操作的动作不同
* */
class Res
{
String name;
String sex;
}
class Input implements Runnable
{
private Res res;
Input(Res res)
{
this.res =res;
}
@Override
public void run() {
int x=0;
while (true) {
if(x==0)
{
res.name = "mike";
res.sex = "man";
}
else
{
res.name = "丽丽";
res.sex = "女女女女女";
}
x = (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res res;
Output(Res res)
{
this.res =res;
}
@Override
public void run() {
while (true) {
System.out.println(res.name+"......"+res.sex);
}
}
}

class Test
{
public static void main(String[] args) {
Res res = new Res();

Input i = new Input(res);
Output o = new Output(res);

Thread t1 = new Thread(i);
Thread t2 = new Thread(o);

t1.start();
t2.start();
}
}


运行结果:
线程不安全
[img]http://dl.iteye.com/upload/picture/pic/132767/127b949d-a38b-31f0-81db-c103a6a7b6d7.png[/img]

代码2线程安全:

class Res
{
String name;
String sex;
}
class Input implements Runnable
{
private Res res;
Input(Res res)
{
this.res =res;
}
@Override
public void run() {
int x=0;
while (true) {
synchronized (res) {
if(x==0)
{
res.name = "mike";
res.sex = "man";
}
else
{
res.name = "丽丽";
res.sex = "女女女女女";
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable
{
private Res res;
Output(Res res)
{
this.res =res;
}
@Override
public void run() {
while (true) {
synchronized (res) {
System.out.println(res.name+"......"+res.sex);
}
}
}
}

class Test
{
public static void main(String[] args) {
Res res = new Res();

Input i = new Input(res);
Output o = new Output(res);

Thread t1 = new Thread(i);
Thread t2 = new Thread(o);

t1.start();
t2.start();
}
}


运行结果:
多线程安全;
[img]http://dl.iteye.com/upload/picture/pic/132769/ca2beaa9-143f-36ca-aae8-144385df0d13.png[/img]

[b][size=medium]需求:放入一个值输出一个值;(多线程通讯:等待唤醒机制)[/size][/b]
代码3:

/**
* 线程间通信
* 其实就是多线程在操作同一个资源
* 但是操作的动作不同
*
* wait();
* notify();
* notifyAll();
*
* 都使用在同步中,因为要对持有监视器(锁)的线程操作。
* 所以要使用在同步中,应为只有同步才具有锁。
*
* 为什么这些操作线程的方法要定义Object类中呢?
* 因为这些方法在操作同步中线程时,都必须要标识他们做操作线程只有的锁。
* 只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
* 不可以对不同锁中的线程进行唤醒。
*
* 也就是说,等待和唤醒必须是同一个锁。
*
*而锁可以是任意对象,所以可以任意对象调用的方法定义在Object类中。
* */
class Res
{
String name;
String sex;
boolean flag=false;
}
class Input implements Runnable
{
private Res res;
Input(Res res)
{
this.res =res;
}
@Override
public void run() {
int x=0;
while (true) {
synchronized (res) {
if(res.flag)
{
try {
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x==0)
{
res.name = "mike";
res.sex = "man";
}
else
{
res.name = "丽丽";
res.sex = "女女女女女";
}
x = (x+1)%2;
res.flag=true;
res.notify();
}
}
}
}
class Output implements Runnable
{
private Res res;
Output(Res res)
{
this.res =res;
}
@Override
public void run() {
while (true) {
synchronized (res) {
if(!res.flag){
try {
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(res.name+"......"+res.sex);
res.flag = false;
res.notify();
}
}
}
}


class Test
{
public static void main(String[] args) {
Res res = new Res();

Input i = new Input(res);
Output o = new Output(res);

Thread t1 = new Thread(i);
Thread t2 = new Thread(o);

t1.start();
t2.start();
}
}


运行结果:
符合需求;
[img]http://dl.iteye.com/upload/picture/pic/132771/d29298e5-5475-30ed-81ff-f7a1e24cc212.png[/img]

以上代码优化:
代码4:

class Res
{
private String name;
private String sex;
private boolean flag=false;

public synchronized void set(String name,String sex) {
if(flag)
{
try { this.wait(); } catch (InterruptedException e)
{ e.printStackTrace();}
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out() {
if(!flag)
{
try { this.wait(); } catch (InterruptedException e)
{ e.printStackTrace();}
}
System.out.println(this.name+"......"+this.sex);
flag = false;
this.notify();
}


}
class Input implements Runnable
{
private Res res;
Input(Res res)
{
this.res =res;
}
@Override
public void run() {
int x=0;
while (true) {
if(x==0)
res.set("mike", "man");
else
res.set("丽丽", "女女女女女");
x = (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res res;
Output(Res res)
{
this.res =res;
}
public void run() {
while (true) {
res.out();
}
}
}

class Test
{
public static void main(String[] args) {
Res res = new Res();

new Thread(new Input(res)).start();
new Thread(new Output(res)).start();
}
}


生产消费模式:
多个生产者,多个消费者:
代码5:

/**
* 资源
* */
class Resource
{
private String name;
private int count=1;
private boolean flag = false;

public synchronized void set(String name) {
while(flag)
{
try {wait();//放弃执行权 注意:当被唤醒后,获得执行权接着往下执行,并持有共同锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
notify();
}
public synchronized void out() {
while(!flag)
{
try {wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
flag = false;
notify();
}
}
/**
* 生产者
* */
class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
res.set("+商品+");
}
}
}
/**
* 消费者
* */
class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
res.out();
}
}
}
/**
* 测试
* */
class Test
{
public static void main(String[] args) {
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);

t1.start();
t2.start();
t3.start();
t4.start();
}
}


运行结果:
没有反应了,原因是 这几个线程都放弃执行权了;
[img]http://dl.iteye.com/upload/picture/pic/132773/9fea8226-8831-3959-ad4c-26c7d0e94db5.png[/img]

解决以上问题:
将notify()方法,修改为notifyAll()(比较通用的方式);
运行结果图:
运行结果OK了;
[color=red][size=medium]问题1:但是 notifyAll唤醒了所有线程包括本方的线程,要怎样使生产者线程运行完唤醒消费者线程而不是全都唤醒?[/size][/color]
[img]http://dl.iteye.com/upload/picture/pic/132775/1a7d6121-330f-3de7-9905-4d301cd666be.png[/img]

[b][size=large]用Lock来替代sysynchronized :[/size][/b]

代码4使用lock实现方式:
代码6使用lock实现多线程 生产消费模式 一对一:


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 资源
* */
class Resource
{
private String name;
private int count=1;
private boolean flag = false;

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

public void set(String name) throws InterruptedException {
lock.lock();
try
{
while(flag)
{
condition.await();
}
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition.signal();//唤醒 下一个线程
}
finally
{
lock.unlock();//释放资源
}
}
public void out() throws InterruptedException {
lock.lock();
try
{
while(!flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
flag = false;
condition.signal();//唤醒 下一个线程
}
finally
{
lock.unlock();//释放资源
}
}
}
/**
* 生产者
* */
class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者
* */
class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 测试
* */
class Test
{
public static void main(String[] args) {
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);
Thread t4 = new Thread(con);

t1.start();
t4.start();
}
}


代码5的修改版使用lock实现方式:
代码7使用lock实现多线程生产消费模式 多对多:
代码7:

/**
* 资源
* */
class Resource
{
private String name;
private int count=1;
private boolean flag = false;

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

public void set(String name) throws InterruptedException {
lock.lock();
try
{
while(flag)
condition.await();
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition.signalAll();//唤醒所有使用共享对象的线程
}
finally
{
lock.unlock();//释放资源
}
}
public void out() throws InterruptedException {
lock.lock();
try
{
while(!flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
flag = false;
condition.signalAll();
}
finally
{
lock.unlock();//释放资源
}
}
}
/**
* 生产者
* */
class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者
* */
class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 测试
* */
class Test
{
public static void main(String[] args) {
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);t1.start();
Thread t3 = new Thread(con);t3.start();

Thread t2 = new Thread(pro);t2.start();
Thread t4 = new Thread(con);t4.start();
}
}


[size=medium][color=blue]现在使用lock 的新特性解决代码5中的问题1;[/color][/size]

一个lock上可以有多个condition :
代码8:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 资源
* JDK1.5 中提供了多线程升级解决方案
* 将synchronized替换成Condition对象。
* 将Object中的wait,notify,nottfyAll,替换了Condition对象。
* 该对象可以使用Lock锁进行获取。
* 该示例中,实现了本方只唤醒对方的操作。
* */
class Resource
{
private String name;
private int count=1;
private boolean flag = false;

private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();//锁条件
private Condition condition_con = lock.newCondition();//

public void set(String name) throws InterruptedException {
lock.lock();
try
{
while(flag)
condition_pro.await();
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();//唤醒某个线程
}
Finally
{
lock.unlock();//释放资源 一定要执行
}
}
public void out() throws InterruptedException {
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();//释放资源
}
}
}
/**
* 生产者
* */
class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者
* */
class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run() {
while (true) {
try {
res.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 测试
* */
class Test
{
public static void main(String[] args) {
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);t1.start();
Thread t3 = new Thread(con);t3.start();

Thread t2 = new Thread(pro);t2.start();
Thread t4 = new Thread(con);t4.start();
}
}


[size=small]Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。 [/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值