线程间通信问题
/**
* 线程间通信问题
* 其实就是多个线程在操作通过一个资源,但是操作的动作不同.
*
* 同步的前提:
* 1.必须要有两个或者两个以上的线程
* 2.必须是多个线程使用同一个锁
*
* 等待唤醒机制
*
* wait()
* notify()
* notifyAll();
*
* 都使用在同步中,因为要对持有监视器的线程操作,所以要使用在 同步中,因为只有 同步才具有锁.
*
* 为什么这些操作线程的方法要定义在Object类中呢?
* 因为 这些方法 在操作同步中线程时,都必须要表示他们所操作线程的只有的锁.
* 只有 同一个锁上的 被等待线程,可以被同一个锁上的notify唤醒
* 不可以对不同锁中的线程进行唤醒.
*
* 也就是,等待和唤醒 必须是同一个锁
* 而锁可以是任意对象,所以可以被任意对象调用的 方法定义在 Object中
*
*
*
*/
class Resource{
String name;
String sex;
boolean flag=false; //表示没有值
}
//复制
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r=r;
}
//Object obj=new Object();
public void run(){
int x=0;
while(true){
synchronized(r){ //obj -->this--> input.class(Output.class,InputOutputDemo.class)-->r
if(r.flag){
try {
r.wait(); //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(x==0){
r.name="mike";
r.sex="man";
}else{
r.name="丽丽";
r.sex="女女女女";
}
r.flag=true;
r.notify();//唤醒 输出线程 通常会唤醒 线程池中 第一被等待的线程
}
x=(x+1)%2;
}
}
}
//取出后 然后输出
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r=r;
}
//Object obj=new Object();
public void run(){
while(true){
synchronized(r){ //obj -->this--> input.class(Output.class,InputOutputDemo.class)-->r
if(!r.flag)
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(r.name+"--------------"+r.sex);
r.flag=false;
r.notify();
}
}
}
}
public class InputOutputDemo {
public static void main(String[] args) {
Resource r=new Resource();
Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
优化上面的 等待唤醒机制
/**
* 线程间通信问题
* 其实就是多个线程在操作通过一个资源,但是操作的动作不同.
*
* 同步的前提:
* 1.必须要有两个或者两个以上的线程
* 2.必须是多个线程使用同一个锁
*
* 等待唤醒机制
*
* 对上面的程序进行优化
*/
class Resource{
private String name;
private String sex;
private boolean flag=false; //表示没有值
public synchronized void setValue(String name,String sex){
if(flag){
try{
this.wait(); //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.name=name;
this.sex=sex;
flag=true;
this.notify();
}
public synchronized void out(){
if(!flag){
try{
this.wait(); //线程运行的时候,程序会在内存中创建线程池,等待的线程会存在线程中
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(name+"--------------"+sex);
flag=false;
this.notify();
}
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r=r;
}
//Object obj=new Object();
public void run(){
int x=0;
while(true){
if(x==0){
r.setValue("mike", "man");
}else{
r.setValue("莉莉", "女女");
}
x=(x+1)%2;
}
}
}
//取出后 然后输出
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r=r;
}
//Object obj=new Object();
public void run(){
while(true){
r.out();
}
}
}
public class InputOutputDemo {
public static void main(String[] args) {
Resource r=new Resource();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
/*Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();*/
}
}
线程间通信 ,生产者 和消费者
/** 线程间通信 ,生产者 和消费者
*
* 发现 上面的 等待唤醒机制 中 如果 线程数 超过过两个 使用 notify 就有问题了
* 原因 就是 当一个线程等待后 被其他线程 唤醒 就不会判断 flag 为真 为假 ,这样就会在某一时间段就会 生产多个商品 或者 消费多个商品
*
*/
class Resouce{
private String name;
private int count=1;
private boolean flag=false;
// while(true){ //t1 t3 循环一次后发现 不一定
public synchronized void setValue(String name){
while(flag)
try {
this.wait();
} catch (InterruptedException e) {// t1 (1等待--->5运行 ) t3 (2等待 --6 运行)
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name=name+"...."+count++;
System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name);
flag=true;
//this.notify() // 只唤醒线程中 最先等待那一个线程
this.notifyAll();
}
//}
public synchronized void out(){
while(!flag)
try {
this.wait();// t1 (3等待) t3 (4等待)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"...........消费者............."+this.name);
flag=false;
this.notifyAll();
}
}
class Producer implements Runnable{
Resouce r;
Producer(Resouce r){
this.r=r;
}
public void run(){
while(true){
r.setValue("+商品+");
}
}
}
class Consumer implements Runnable{
Resouce r;
Consumer(Resouce r){
this.r=r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Resouce r=new Resouce();
Producer p=new Producer(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(c);
//使用 两个线程的时候 仿照 之前的 例子是没有问题,如果 超过两个线程后就会有问题了
Thread t3=new Thread(p);
Thread t4=new Thread(c);
t1.start();
t2.start();
// 因此 使用上 了 while notifyAll 才解决这个问题 这是JDK1.5之前 的程序都这么干的
t3.start();
t4.start();
}
使用 JDK1.5的新特性 来优化上面的代码
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* JDK5.0 中提供了 多线程 升级解决方案
* 将同步Synchronized 替换成 显示的 Lock机制
* 将 Object 中的 wait notify notifyall 替换成了 Condition对象中 await signal signalAll
*
* Condition 对象可以用 Lock 锁,进行获取
*
* 在该实例中 实现了本方 只唤醒 对方的操作
*
*/
class Resouce{
private String name;
private int count=1;
private boolean flag=false;
private Lock lock=new ReentrantLock();
private Condition c_proc=lock.newCondition(); //声明 一个锁中 监视器对象
private Condition c_cons=lock.newCondition(); //声明 一个锁中 监视器对象
public void setValue(String name) throws InterruptedException{
lock.lock(); //synchronized
try{
while(flag)
c_proc.await(); //this.wait()
this.name=name+"...."+count++;
System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name);
flag=true;
}finally{ //释放锁的动作一定要执行
//this.notify() // 只唤醒线程中 最先等待那一个线程
//this.notifyAll();
c_cons.signal(); //只需要唤醒 消费者中的一个就可以了 不需要 All
}
}
public void out() throws InterruptedException{
lock.lock(); //synchronized 一看就知道是同一个锁 是吧 呵呵
try{
while(!flag)
c_cons.await(); // this.wait();
System.out.println(Thread.currentThread().getName()+"...........消费者............."+this.name);
flag=false;
}finally{
//this.notifyAll();
c_proc.signal(); // 唤醒生产者中的一个就可以了
}
}
}
//生产者
class Producer implements Runnable{
Resouce r;
Producer(Resouce r){
this.r=r;
}
public void run(){
while(true){
try {
r.setValue("+商品+");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//消费者
class Consumer implements Runnable{
Resouce r;
Consumer(Resouce r){
this.r=r;
}
public void run(){
while(true){
try {
r.out();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Resouce r=new Resouce();
Producer p=new Producer(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(c);
Thread t3=new Thread(p);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}