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()方法--当前线程被阻塞并释放该对象的互斥锁
相关文章推荐
- Java学习总结之第十三章 多线程
- Java多线程-概念与原理
- Java多线程与并发应用-(4)-传统线程通信技术试题
- Java的多线程终止,守护线程
- 【转载】Java多线程,判断其他线程是否结束的三种方法
- Java多线程编程要点
- java基本教程之线程休眠 java多线程教程
- 黑马程序员—java多线程
- java多线程解说【拾肆】_线程池
- Java 多线程(六) synchronized关键字详解
- Java多线程
- Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
- JAVA多线程之——Thread中start()和run()的区别
- 使用Java理解程序逻辑第十三章
- java中如何实现多线程
- java多线程学习--java.util.concurrent (转载)
- Java多线程交替执行任务
- (一)java多线程之Thread
- Java多线程,交替输出121212
- java-多线程1