今天看了项目的源码。看到了每个方法都用synchronized 标注的方法,代码也懒得看了,幸好我们用户少,越来越少。。。。不需要那么高的并发。。。
闲话不多说,早上说了观察者模式。突然想到了是不是可以用生产消费模式。一边做任务,一边处理任务,中间存任务状态,会不会耦合度少点,而且能做到线程安全(后来看了下,没有做到,必须在task 线程里面搞安全。回头多看看多线程和并发的知识)
上代码:
1.message 类,就是生产者和消费者中间那个东西。一个生产一个消费。。。。。
package testProductIssue; public class Message { private String msg; public Message(String msg){ this.msg = msg; } public String getMsg(){ return msg; } }
2.生产者:
package testProductIssue; import java.util.concurrent.BlockingQueue; public class Product implements Runnable{ private BlockingQueue<Message> que ; public Product(BlockingQueue<Message> que){ this.que = que; } @Override public void run() { for(int i=0 ; i <10;i++){ Message e = new Message("message:"+i); try { que.put(e); System.out.println("this is P "+e.getMsg()); Thread.sleep(1000); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } Message e = new Message("exit"); try { que.put(e); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }
3.消费者
package testProductIssue; import java.util.concurrent.BlockingQueue; public class Custom implements Runnable{ private BlockingQueue<Message> que; public Custom(BlockingQueue<Message> que){ this.que = que; } @Override public void run() { // TODO Auto-generated method stub try { Message msg ; //这里我看了下BlockingQueue的take方法,调用一次这个方法,这个queue里面的 //东西就被取走了,所以就直接写在while里面了,这个如果设置成永远等下去,就等于 //我上一个里面那个wait了。。感觉一个效果。 while((msg=que.take()).getMsg()!="exit"){ //先让他休息一下,要不可能那边放上去还没来得及打印到命令行这边就输出了,会造成困扰 Thread.sleep(2000); System.out.println("this is C "+msg.getMsg()); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
4.测试类
package testProductIssue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class TestIssue { public static void main(String[] args) throws InterruptedException { BlockingQueue<Message> msg = new ArrayBlockingQueue<Message>(5); Thread pro = new Thread(new Product(msg)); Thread cus = new Thread(new Custom(msg)); pro.start(); cus.start(); pro.join(); } }
这里的BlockingQueue要说一下,这是concurrent 包下面的一个接口,后面ArrayBlockingQueue是一个实现类,这个有什么特点呢。首先是线程安全的。而且有一个特点就是如果这个queue里面空的,则去操作会处于阻塞状态,如果这个queue是满的,添加操作处于阻塞状态,这里我设置queue的大小是5,下面我吧设置成2的输出到控制台 就能体会到这个阻塞的感觉了。。。
this is P message:0 this is P message:1 this is P message:2 this is C message:0 //取出一个数 this is P message:3 //才能放进去一个 this is C message:1 //取出一个 this is P message:4 //才能放进去一个 this is C message:2 this is P message:5 this is C message:3 this is P message:6 this is C message:4 this is P message:7 this is C message:5 this is P message:8 this is C message:6 this is P message:9 this is C message:7 this is C message:8 this is C message:9
然后 生产者消费者就是这样呀,两个线程 一个生产 一个消费,把东西放到超市(中间的那个queue) 然后各取所需。额貌似就这样,刚刚吃过晚饭,晚上回家继续研究,现在脑子里面啥都没有。。想起来再更新吧。。。。
当然,生产者消费者模式还有另一种实现,就是在中间缓存处不使用BlockingQueue 而是用其他的存储单位,这样的话,很容易造成线程不同步的问题,就是我们所说的多线程并发导致的数据不同步了,我网上看了下,可以用volatile关键字来定义容器中中得message,这样存取就不会乱掉。因为volatile是永远从内存中读得。现在想想这个关键字和 threadlocal完全是对立吧,一个是暴力同步内存中得。一个是保存对象副本。分场合来使用这两个东西吧。。。