Java多线程间的通信问题扩展

到底什么是线程间的通信?

线程间需要通过一些协调性的通信,实现共同完成同一件任务,简单说就是,你想做这件事,我也想做这件事,我们两个相互交流,共同做这件事,而共同任务的同步性的实现,就必须通过同步锁,每一个对象实例都有自己的一把锁,当一个线程想要对这个任务进行处理的时候,就必须获得这把锁。线程之间锁的释放与获取,是通过Object类中的wait()/notify()方法实现的。wait()方法是将当前拥有锁的线程至于等待状态让其释放锁,而notify()方法是唤醒其他线程使其具备执行资格,过来拿这个锁,拿到这个锁后才具备了执行权。

需要注意的是,一定要确保wait()方法是出于同步区域中,才会拥有锁,而同样至于同步区域的Thread.sleep()方法,只会让线程在指定的时间段内睡眠,而不会释放锁

线程间的通信主要通过两种方式:

1.共享内存

初次学习的时候,已经写过,写个简单点的

public class Main{
	public static void main(String[] args){
		MemoryThread MyThread = new MemoryThread();
		MyThread.getThread().start();
		MyThread.getThread().start();
	}
}
class MemoryThread {
	private int data;
	public MemoryThread() {
		// TODO Auto-generated constructor stub
		data = 0;
	}
	public class Inside implements Runnable{

		public void run() {
			while(true){
				synchronized (this) {
					System.out.println(Thread.currentThread().getName()+"--:--"+(++data));
				}
			}
		}
	}
	public Thread getThread(){
		return new Thread(new Inside());
	}
}

ps:共享内存这中通信方式,存在不稳定性,有时候会出现问题

2.管道流

通过管道流实现线程间的通信,主要是将管道流连接到线程。

class Producer implements Runnable{

	private PipedOutputStream pout = null;
	public Producer(PipedOutputStream pout) {

		this.pout = pout;
	}
	public void run() {
		int x = 1;
		// TODO Auto-generated method stub
		synchronized (this) {

			while(true){
				synchronized (this) {
						try {
							System.out.println("Producer set "+x);
						pout.write(x);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
class Customer implements Runnable{

	private PipedInputStream pin = null;
	public Customer(PipedInputStream pin) {

		this.pin = pin;
	}
	public void run() {

			while(true){
				synchronized(this){
				try {
					System.out.println("Customer get "+pin.read());
				} catch (Exception e) {
					// TODO: handle exception
				}

			}
		}

	}
}
public class Main{

	public static void main(String[] args) {

		PipedInputStream pin = new PipedInputStream();
		PipedOutputStream pot = new PipedOutputStream();
		try{
			pot.connect(pin);
		}catch(Exception e){
			e.printStackTrace();

		}
		new Thread(new Producer(pot)).start();
		new Thread(new Customer(pin)).start();

	}
}

ps:因为管道流的read方法是阻塞式的,数据的同步和并发会出现问题

由线程间的通信问题进而可以提升到多生产者多消费者问题

多生产者多消费者问题解决方法一般分为两种:

1.采用一种机制实现生产者/消费者间的同步(常用,效率高)

2.采用管道流的方式

解决同步问题,一般都是synchronized函数或代码块+while+notifyAll的方式,接口Lock的出现,有了更加灵活的操作,可以支持多个监听器,以此来实现锁更广泛的操作

此处直接演示Lock的方式

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

/**
 * Created by kevy on 14-12-01.
 */

/**
 * 描述:仓库存储着货物,每个货物都对应一个编号
 * 仓库货满时,生产者不能存放货物。 仓库为空时,消费者不能拿走货物
 * 面向对象的思想考虑问题:涉及的对象,生产者,消费者,货物,仓库
 * 生产者,消费者对应着同一个仓库,仓库对应着不同的货物
 */
class Goods {
    private String name;
    private int num;
    Goods(String name,int num){
        this.name = name;
        this.num = num;
    }
    public String getName() {
        return name;
    }
    public int getNum() {
        return num;
    }
}
class StoreHouse{
    public final static int SIZE = 10;
    private Goods[] goodses = new Goods[SIZE];//定义仓库储存大小

    private Lock lock = new ReentrantLock();//创建锁
    private Condition Pro_lock = lock.newCondition();//创建生产者监视器
    private Condition Cus_lock = lock.newCondition();//创建消费者监视器
    private int putnum = 0,count = 0,takenum = 0;

    public void set(Goods good){
        lock.lock();
        try{
            while(count==SIZE){
                try{
                    Pro_lock.await();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            Thread.sleep(100);//延时100
            goodses[putnum] = good;
            System.out.println(Thread.currentThread().getName()+"++++生产++++"+
                    good.getName()+good.getNum());
            if(++putnum==SIZE) putnum = 0;
            count++;
            Cus_lock.signal();

           }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void out(){
        lock.lock();
        try{
            while(count==0){
                try{
                    Cus_lock.await();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            Thread.sleep(100);//延时100
            Goods item = goodses[takenum];
            if(++takenum==SIZE) takenum = 0;
            --count;
            System.out.println(Thread.currentThread().getName()+"----消费----"+
                item.getName()+item.getNum());
            Pro_lock.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
class Producer implements Runnable{
    private StoreHouse storeHouse = null;
    private String Goodname = null;
    Producer(StoreHouse storeHouse,String goodname){
        this.storeHouse = storeHouse;
        this.Goodname = goodname;
    }

    public void run() {
        int NUM = 1;
        while(true){
            storeHouse.set(new Goods(Goodname,NUM++));
        }
    }
}
class Customer implements Runnable{
    private StoreHouse storeHouse = null;
    Customer(StoreHouse storeHouse){
        this.storeHouse = storeHouse;
    }

    public void run() {
        while(true){
            storeHouse.out();
        }
    }
}
public class Main {
    public static StoreHouse storeHouse;
    public static void main(String[] args){

        storeHouse = new StoreHouse();
        Runnable p = new Producer(storeHouse,"卫生纸");
        Runnable p1 = new Producer(storeHouse,"Java技术-核心卷I");

        Runnable c = new Customer(storeHouse);
        Runnable c1 = new Customer(storeHouse);

        Thread proThread1 = new Thread(p);//生产者线程
        Thread proThread2 = new Thread(p1);
        Thread cusThread1 = new Thread(c);//消费者线程
        Thread cusThread2 = new Thread(c1);

        proThread1.start();  cusThread1.start();
        proThread2.start();  cusThread2.start();

    }
}

时间: 2024-08-15 04:21:28

Java多线程间的通信问题扩展的相关文章

Java 多线程间的通讯

在前一小节,介绍了在多线程编程中使用同步机制的重要性,并学会了如何实现同步的方法来正确地访问共享资源.这些线程之间的关系是平等的,彼此之间并不存在任何依赖,它们各自竞争CPU资源,互不相让,并且还无条件地阻止其他线程对共享资源的异步访问.然而,也有很多现实问题要求不仅要同步的访问同一共享资源,而且线程间还彼此牵制,通过相互通信来向前推进.那么,多个线程之间是如何进行通信的呢? 解决思路 在现实应用中,很多时候都需要让多个线程按照一定的次序来访问共享资源,例如,经典的生产者和消费者问题.这类问题描

java多线程之间的通信

如何让两个线程依次执行?那如何让 两个线程按照指定方式有序交叉运行呢?四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的三个运动员各自准备,等到三个人都准备好后,再一起跑子线程完成某件任务后,把得到的结果回传给主线程1.如何让两个线程依次执行?#Copypublic static void main(String[] args) {demo1();/结果: t1>>pirnt:1t2>>pirnt:1t2>>pir

JAVA学习第二十六课(多线程(五))- 多线程间的通信问题

一.线程间的通信 实例代码: 需求是:输入一个姓名和性别后,就输出一个姓名和性别 class Resource { String name; String sex ; } class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized (r) { if(x==0) { r.name =

Java多线程之线程通信

线程通信的例子:使用两个线程打印 1-100,线程1.线程2交替打印.涉及到的三个方法:wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器.notify():一旦执行此方法,就会唤醒被wait的一个线程.如果有多个线程被wait,就唤醒优先级高的那个.notifyAll():一旦执行此方法,就会唤醒所有被wait的线程. 说明:1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中.2.wait(),notify(),notifyA

黑马程序员-学习日记(多线程间的通信)

 ------Java EE培训.Android培训.iOS培训.期待与您交流! ------- 示例: //将资源封装成对象 class Resour { String name; String gender; } //将线程执行的任务封装成对象 class Input implements Runnable { private Resour r; Input(Resour r) { this.r = r; } public void run() { int x =0; while(true)

多线程间的通信问题之交替打印

1.要实现的效果,直接上图: 1.具体逻辑很清晰,就是通过多线程来实现直接上代码,lock控制相同的输入或输出线程的同步,resource控制着输入和输出线程的同步 class Resource { private String name; private String sex; private boolean flag; public void setName(String name) { this.name=name; } public void setSex(String sex) { t

java 多线程 day04 线程通信

package com.czbk.thread; /** * Created by chengtao on 17/12/3. * 需求: 子线程先运行10次,然后主线程运行 100次,依次运行50次 * wait(): 等待 如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒. notify(): 唤醒 唤醒线程池等待线程其中的一个. notifyAll() : 唤醒线程池所有等待 线程. wait与notify方法要注意的事项:

java多线程详解(6)-线程间的通信wait及notify方法

Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New):线程对象已经产生,但尚未被启动,所以无法执行.如通过new产生了一个线程对象后没对它调用start()函数之前.(2). 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它. 当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它

java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)

本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: [java] view plain copy print? package com.zejian.test; /** * @author zejian * @time 2016年3月12日 下午2:55:42 * @decrition 模拟卖票线程 */ public class Ticket implements Runnable { //当前拥有的票数 private