java进程通信问题

Little BigUs 2021-04-29 11:32:28
package ThreadTest;


import java.util.ArrayList;
import java.util.List;

public class FirstThread {
static List<Object> goods = new ArrayList<>(); //储存物品的仓库,最多储存1
public static void main(String[] args) throws InterruptedException {
Producer thread1 = new Producer();
Consumer thread2 = new Consumer();

Thread p1 = new Thread(thread1, "生产者1");
Thread p2 = new Thread(thread1, "生产者2");
Thread p3 = new Thread(thread1, "生产者3");
Thread c1 = new Thread(thread2, "消费者1");
Thread c2 = new Thread(thread2, "消费者2");
Thread c3 = new Thread(thread2, "消费者3");

p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
c3.start();

}
static class Producer implements Runnable {

@Override
public void run() {
// TODO Auto-generated method stub
int num = 0;
while(true) {
synchronized (goods) {
if(goods.size()==0) {
goods.add("商品" + ++num);
System.out.println(Thread.currentThread().getName()+"生产了第"+num+"个产品");
}
else if(goods.size()>0)
try {
goods.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {

@Override
public void run() {
// TODO Auto-generated method stub
int num = 0;
while(true) {
synchronized (goods) {
if(goods.size()>0) {
goods.remove("商品"+ ++num);
System.out.println(Thread.currentThread().getName()+"消费了第"+num+"个产品");
}
else if (goods.size()==0)
goods.notify();;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

}
}

为什么所有的生产者不是共用一个num,输出时每个生产者都会输出1,2...。我按照书上的例子可以实现共享,是不是这里是内部类的问题,但是如果不用内部类我又怎么实现生产者和消费者之间的通信呢,
顺便再问一个问题,那就是我按照书上的例子敲的,但是每次执行的结果都是几乎由一个窗口完成全部售票,没有达到上下两张票的窗口一定不同,代码如下:
按理来说sleep(100)会保证不让同一线程连续执行
package ThreadTest;

class SaleThread2 implements Runnable {
int tickets = 10;
Object lock = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
synchronized (lock) {
if(tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets-- +"张票");
}
}
}
}

}

public class Example12 {
public static void main(String[] args) {
SaleThread2 st = new SaleThread2();
new Thread(st, "窗口1").start();
new Thread(st, "窗口2").start();
new Thread(st, "窗口3").start();
new Thread(st, "窗口4").start();
}
}
...全文
1736 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiaoxiangqing 2021-05-06
  • 打赏
  • 举报
回复
public class FirstThread { static List<Object> goods = new ArrayList<>(); //储存物品的仓库,最多储存1 static int num = 0; public static void main(String[] args) throws InterruptedException { Producer thread1 = new Producer(); Consumer thread2 = new Consumer(); Thread p1 = new Thread(thread1, "生产者1"); Thread p2 = new Thread(thread1, "生产者2"); Thread p3 = new Thread(thread1, "生产者3"); Thread c1 = new Thread(thread2, "消费者1"); Thread c2 = new Thread(thread2, "消费者2"); Thread c3 = new Thread(thread2, "消费者3"); p1.start(); p2.start(); p3.start(); c1.start(); c2.start(); c3.start(); } static class Producer implements Runnable { @Override public void run() { // TODO Auto-generated method stub while(true) { synchronized (goods) { if(goods.size()==0) { goods.add("商品" + ++num); System.out.println(Thread.currentThread().getName()+"生产了第"+num+"个产品,goods.size():"+goods.size()); } else if(goods.size()>0) try { goods.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } static class Consumer implements Runnable { @Override public void run() { // TODO Auto-generated method stub //int num = 0; while(true) { synchronized (goods) { if(goods.size()>0) { goods.remove("商品"+ num); System.out.println(Thread.currentThread().getName()+"消费了第"+num+"个产品,goods.size():"+goods.size()); } else if (goods.size()==0) goods.notify();; } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
heyingss 2021-05-06
  • 打赏
  • 举报
回复
学习了,收藏!
老王就是我 2021-05-06
  • 打赏
  • 举报
回复
第一个问题,每个线程都独享所有非静态成员变量,你可以这么理解——每个线程都相当于new了一个新对象。非本对象的非静态成员,和本对象有什么关系呢? 第二个问题,volatile,是解决线程共享变量的一个解决方案,它最大的作用不是解决通信问题,而是指令重排序的问题。 你可以百度下sync同步块,同步锁的对象是自动加上volatile的
luj_1768 2021-05-05
  • 打赏
  • 举报
回复
有一个问题,consumer 代码中,++num的使用有疑问,应该是num==0时、对应的是listArray的队尾,这时、对num应该使用减法操作。 开始的代码,声明了一个列表队列,用于记录不同商品的库存,应该是像堆栈那样处理每一个列表、像数组那样处理不同列表的访问。 声明了producer 和consumer 来实现列表队列中的数据操作,同时实现了各自三个线程的服务池。 producer 和consumer 使用num作为操作量,预置为0对应于数据尾部,++num,实现操作量加一,producer 对于num使用加法操作增长数据记录,consumer 对于num使用减法操作减短数据记录。 示例代码可能存在少量错误,也许是故意的,如果不读懂代码就无法使用例程。
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 9 楼 qq_39936465的回复:
我发现问题就是出在你把int num=0 写在run代码块内了,我也不知道那本书上教你这么写的。 要知道start其实就是执行run代码块的,你把num变为了run代码块的局部变量,造成同步不起效了,这里num直接变为全局变量即可。
嗯,是我抄错了
qq_39936465 2021-04-30
  • 打赏
  • 举报
回复
我发现问题就是出在你把int num=0 写在run代码块内了,我也不知道那本书上教你这么写的。 要知道start其实就是执行run代码块的,你把num变为了run代码块的局部变量,造成同步不起效了,这里num直接变为全局变量即可。
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 6 楼 qq_39936465的回复:
[quote=引用 4 楼 m0_45972156 的回复:][quote=引用 3 楼 长江水面写日记的回复:]volatile只能修饰final,谁教给你的? 第二段你加了锁,在锁里sleep又不会释放锁,书上是这么写的?
没有,我没学过volatile,我只是按照他说的添加volatile后编译器报错,说应该修饰final[/quote] 你没看我添加在哪里么?不然我贴程序干么?[/quote] 懂了,谢谢老哥
qq_39936465 2021-04-30
  • 打赏
  • 举报
回复
volatile和final类似,只能申明一次,所以不能在run程序块内申明
qq_39936465 2021-04-30
  • 打赏
  • 举报
回复
引用 4 楼 m0_45972156 的回复:
[quote=引用 3 楼 长江水面写日记的回复:]volatile只能修饰final,谁教给你的? 第二段你加了锁,在锁里sleep又不会释放锁,书上是这么写的?
没有,我没学过volatile,我只是按照他说的添加volatile后编译器报错,说应该修饰final[/quote] 你没看我添加在哪里么?不然我贴程序干么?
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 3 楼 长江水面写日记的回复:
volatile只能修饰final,谁教给你的? 第二段你加了锁,在锁里sleep又不会释放锁,书上是这么写的?
第二段懂了,非常感谢
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 3 楼 长江水面写日记的回复:
volatile只能修饰final,谁教给你的? 第二段你加了锁,在锁里sleep又不会释放锁,书上是这么写的?
没有,我没学过volatile,我只是按照他说的添加volatile后编译器报错,说应该修饰final
  • 打赏
  • 举报
回复
volatile只能修饰final,谁教给你的? 第二段你加了锁,在锁里sleep又不会释放锁,书上是这么写的?
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 1 楼 qq_39936465 的回复:
[quote=引用 楼主 m0_45972156 的回复:] 为什么所有的生产者不是共用一个num,输出时每个生产者都会输出1,2...。我按照书上的例子可以实现共享,是不是这里是内部类的问题,但是如果不用内部类我又怎么实现生产者和消费者之间的通信呢, 顺便再问一个问题,那就是我按照书上的例子敲的,但是每次执行的结果都是几乎由一个窗口完成全部售票,没有达到上下两张票的窗口一定不同,代码如下: 按理来说sleep(100)会保证不让同一线程连续执行
第一段程序,num加入同步。

static class Producer implements Runnable {
    	volatile int num = 0;
        @Override
        public  void run() {
            // TODO Auto-generated method stub
            while(true) {
                synchronized (goods) {
                    if(goods.size()==0) { 
                        goods.add("商品" + ++num);
                        System.out.println(Thread.currentThread().getName()+"生产了第"+num+"个产品");
                    }
                    else if(goods.size()>0)
                        try {
                            goods.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
}
    static class Consumer implements Runnable {
    	 volatile int num = 0;
        @Override
        public void run() {
            // TODO Auto-generated method stub
          
            while(true) {
                synchronized (goods) {
                    if(goods.size()>0) {
                        goods.remove("商品"+ ++num);
                        System.out.println(Thread.currentThread().getName()+"消费了第"+num+"个产品");
                    }
                    else if (goods.size()==0)
                        goods.notify();;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
         
    }
第2段程序并不能说明什么问题,数字太小偶然性大,你试着把票数调到100 结果会不一样。[/quote] 首先非常感谢你的回答,但是volatile修饰num会报错,volatile只能修饰final类型。 第二段程序每个线程执行时会sleep(100),所以应该不存在什么偶然性,应该必然不会让同一线程连续执行
qq_39936465 2021-04-30
  • 打赏
  • 举报
回复
引用 楼主 m0_45972156 的回复:
为什么所有的生产者不是共用一个num,输出时每个生产者都会输出1,2...。我按照书上的例子可以实现共享,是不是这里是内部类的问题,但是如果不用内部类我又怎么实现生产者和消费者之间的通信呢, 顺便再问一个问题,那就是我按照书上的例子敲的,但是每次执行的结果都是几乎由一个窗口完成全部售票,没有达到上下两张票的窗口一定不同,代码如下: 按理来说sleep(100)会保证不让同一线程连续执行
第一段程序,num加入同步。

static class Producer implements Runnable {
    	volatile int num = 0;
        @Override
        public  void run() {
            // TODO Auto-generated method stub
            while(true) {
                synchronized (goods) {
                    if(goods.size()==0) { 
                        goods.add("商品" + ++num);
                        System.out.println(Thread.currentThread().getName()+"生产了第"+num+"个产品");
                    }
                    else if(goods.size()>0)
                        try {
                            goods.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
}
    static class Consumer implements Runnable {
    	 volatile int num = 0;
        @Override
        public void run() {
            // TODO Auto-generated method stub
          
            while(true) {
                synchronized (goods) {
                    if(goods.size()>0) {
                        goods.remove("商品"+ ++num);
                        System.out.println(Thread.currentThread().getName()+"消费了第"+num+"个产品");
                    }
                    else if (goods.size()==0)
                        goods.notify();;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
         
    }
第2段程序并不能说明什么问题,数字太小偶然性大,你试着把票数调到100 结果会不一样。
Little BigUs 2021-04-30
  • 打赏
  • 举报
回复
引用 11 楼 冰思雨的回复:
首先,楼主的这个代码,使用的是多线程技术,不是多进程技术,所以,不能称之为进程通信。 其次,多线程技术中,多线程可以通过共享变量的方式来交互数据,一般情况下,我们把数据一致性问题称为线程安全,至少我是这样理解的。 再次,楼主的 Java 基础还是有些薄弱,建议先巩固一下 Java 基础(比如,语法相关的内容)在来编写多线程方法的程序吧。 变量的可见域,这个词,楼主有听说过吗? 函数内声明的变量,可见域只能在函数内部,函数结束后(正常返回或抛出异常)局部变量会被回收。这就是函数的封装性,函数内部的变量,只能在函数内部访问。上面第二点中说过,多线程技术可以通过共享变量的方式来进行数据的互访,那么,要想 num 被多个线程访问(读写操作),那就不要在 run 函数里面声明这个变量。 最后,既然使用了 wait-notify 完成数据同步了,就没有必要使用Thead.sleep()了吧,我是真没看懂。sleep 的作用只是让线程让出CPU的时间片,和线程恢复后的执行顺序毫无关系,而且,为了提高执行效率,我们的代码中是非常机会有sleep调用的。 还有,while(true) 中 true 条件的死循环,也是编程中非常忌讳的存在,我们写程序,尤其是多线程技术的程序,都要讲究优雅退出的,你整了一个 true 条件的死循环,怎么结束程序,只能强制杀死进程了,这种强制杀死进程的方式,我们是非常不推荐使用的,复杂一些的程序会出现很大的问题。 (举个例子,如果你的程序在结束之前要保存程序执行过程中的一些配置信息,结果,你强制杀死了进程,配置信息没有保存,或者保存了一半,下次启动的时候,要么配置信息是上次执行前的鸟样子,要么就是半个配置文件的信息,启动都有可能报错,从而无法启动了。)
感谢指点,我会好好学基础的
冰思雨 2021-04-30
  • 打赏
  • 举报
回复
首先,楼主的这个代码,使用的是多线程技术,不是多进程技术,所以,不能称之为进程通信。 其次,多线程技术中,多线程可以通过共享变量的方式来交互数据,一般情况下,我们把数据一致性问题称为线程安全,至少我是这样理解的。 再次,楼主的 Java 基础还是有些薄弱,建议先巩固一下 Java 基础(比如,语法相关的内容)在来编写多线程方法的程序吧。 变量的可见域,这个词,楼主有听说过吗? 函数内声明的变量,可见域只能在函数内部,函数结束后(正常返回或抛出异常)局部变量会被回收。这就是函数的封装性,函数内部的变量,只能在函数内部访问。上面第二点中说过,多线程技术可以通过共享变量的方式来进行数据的互访,那么,要想 num 被多个线程访问(读写操作),那就不要在 run 函数里面声明这个变量。 最后,既然使用了 wait-notify 完成数据同步了,就没有必要使用Thead.sleep()了吧,我是真没看懂。sleep 的作用只是让线程让出CPU的时间片,和线程恢复后的执行顺序毫无关系,而且,为了提高执行效率,我们的代码中是非常机会有sleep调用的。 还有,while(true) 中 true 条件的死循环,也是编程中非常忌讳的存在,我们写程序,尤其是多线程技术的程序,都要讲究优雅退出的,你整了一个 true 条件的死循环,怎么结束程序,只能强制杀死进程了,这种强制杀死进程的方式,我们是非常不推荐使用的,复杂一些的程序会出现很大的问题。 (举个例子,如果你的程序在结束之前要保存程序执行过程中的一些配置信息,结果,你强制杀死了进程,配置信息没有保存,或者保存了一半,下次启动的时候,要么配置信息是上次执行前的鸟样子,要么就是半个配置文件的信息,启动都有可能报错,从而无法启动了。)

62,630

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧