您的位置:首页 > 编程语言 > Java开发

java 第十三章 多线程(3)

2012-09-05 17:31 162 查看

线程的同步通信

为避免死锁,就应该让线程在进入阻塞状态时尽量释放其锁定的资源,以为其他的线程提供运行的机会,Object类中定义了几个有用的方法:wait()、notify()、notifyAll()。

wait():被锁定的对象可以调用wait()方法,这将导致当前线程被阻塞并释放该对象的互斥锁,即解除了wait()方法当前对象的锁定状态,其他的线程就有机会访问该对象
notify():唤醒调用wait()方法后被阻塞的线程。每次运行该方法只能唤醒一个线程
notifyAll():唤醒所有调用wait()方法被阻塞的线程
实例,生产者和消费者

package com.hbsi;

//资源类

class Res{

String name;

String sex;

boolean b;

}

//生产者类

class Input implements Runnable{

private Res r;

public Input(Res r){

this.r=r;

}

@Override

public void run() {

int x=0;

while(true){

synchronized(r){

//判断是否需要生产

if(r.b)

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if(x==0){

r.name="张三";

r.sex="男";

}else{

r.name="lisi";

r.sex="nv";

}

r.b=true;

r.notify();

x=(x+1)%2;

}

}

}

}

class Output implements Runnable{

private Res r;

public Output(Res r){

this.r=r;

}

@Override

public void run() {

while(true){

synchronized(r){

if(!r.b)

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(r.name+"..."+r.sex);

r.b=false;

r.notify();

}

}

}

}

public class ThreadDemo {

/**

* @param args

*/

public static void main(String[] args) {

Res s=new Res();

Input in=new Input(s);

Output out=new Output(s);

Thread t1=new Thread(in);

Thread t2=new Thread(out);

t1.start();

t2.start();

}

}

生产者-消费者问题是多线程同步处理的典型问题

有一块生产者和消费者共享的有界缓冲区,生产者往缓冲区放入产品,消费者从缓冲区取走产品,这个过程可以无休止的执行,不能因缓冲区满生产者放不进产品而终止,也不能因缓冲区空消费者无产品可取而终止。

同样代码也可以写成这样,其结果都是一样的:
package com.hbsi;

//资源类

class Res1{

private String name;

private String sex;

private boolean flag;

public synchronized void set(String name,String sex){

if(flag)

try {

wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

this.name=name;

this.sex=sex;

flag=true;

notify();

}

public synchronized void out(){

if(!flag)

try {

wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(name+"....."+sex);

}

}

//生产者类

class Input1 implements Runnable{

private Res1 r;

public Input1(Res1 r){

this.r=r;

}

@Override

public void run() {

int x=0;

while(true){

if(x==0){

r.set("张三","男");

}else{

r.set("lisi","nv");

}

x=(x+1)%2;

}

}

}

//消费者类

class Output1 implements Runnable{

private Res r;

public Output1(Res r){

this.r=r;

}

@Override

public void run() {

while(true){

synchronized(r){

if(!r.b)

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(r.name+"..."+r.sex);

}

}

}

}

public class ThreadDemo2 {

/**

* @param args

*/

public static void main(String[] args) {

Res s=new Res();

Input in=new Input(s);

Output out=new Output(s);

Thread t1=new Thread(in);

Thread t2=new Thread(out);

t1.start();

t2.start();

}

}

其结果均为:
lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

lisi...nv

张三...男

线程B写一次,线程A读一次

在某个时候线程B运行速度比较快,在线程A未读取上一个数据之前,B就写了第二次数据,造成数据遗漏。

在某个时候线程A运行速度比较快,它读完一次数据之后,线程B还没来得及写,线程A又来读第二次。结果线程A读不到数据,导致运行出错。

线程B正在写数据时,线程A也来读取数据,这时可能线程B还没将数据写完,线程A将数据读走,导致程序出错。

解决生产者消费者问题的方法

一种是采用某种机制保持生产者和消费者之间的同步,这种方法有较高的效率并且可控制性较好,比较常用

一种是在生产者和消费者之间建立一个管道,这种方法由于管道缓冲区不易控制及被传输数据对象不易封装等原因,比较少用

线程的同步解决生产者-消费者问题

限制公共缓冲区不能被两个线程同时访问,需要使用互斥锁,即用synchronized来标识同步资源。

但加了互斥锁以后有可能会造出死锁。这时需要wait()方法和notify()方法--当前线程被阻塞并释放该对象的互斥锁
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: