一、背景
如果存在这么个场景,多个线层需要操作(读写)某一对象,但是每个线程之间希望互不影响。就像银行给客户发送邮件,邮件的模板都是一样的,我们可以抽象为一个邮件类,但是发送给每个人的称呼是不一样的,如果采用单线程发送,那么如果发送量比较大的话就会很慢。采用多线程发送,就会存在这样的问题,线程一还没发送,线程二就将邮件的称呼修改了,这样就会导致线程不安全的问题。原型模式正好能解决这样的问题。每个线程拷贝一份邮件对象,各自对拷贝邮件对象操作,相互之间互不影响。
二、概念
原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。java Object已经提供了一个clone方法,原型模式在java中实现更为简单快捷。
三、代码实例
package prototypePattern;
import java.util.Random;
/**
* 邮件类
*
*/
class Mail implements Cloneable {
private String acceptName;// 收件人
private String context;// 内容
public String getAcceptName() {
return acceptName;
}
public void setAcceptName(String acceptName) {
this.acceptName = acceptName;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
@Override
protected Mail clone() throws CloneNotSupportedException {
Mail mail = (Mail) super.clone();
return mail;
}
}
/**
* 发送邮件的线程
*
*/
class SendMail implements Runnable {
private Mail mail;
public SendMail(Mail mail) {
this.mail = mail;
}
@Override
public void run() {
try {
Mail mailClone = this.mail.clone();// 拷贝对象
String name = getRandName();
mailClone.setAcceptName(name);
mailClone.setContext(name + "您好,邮件内容。。。。");
System.out.println(Thread.currentThread().getName() + "发送邮件给-》"
+ mailClone.getAcceptName() + ",内容为:"
+ mailClone.getContext());
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getRandName() {
String source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuffer sb = new StringBuffer();
Random rand = new Random();
for (int i = 0; i < 3; i++) {
sb.append(source.charAt(rand.nextInt(source.length())));
}
return sb.toString();
}
}
public class MailSendCli {
public static void main(String[] args) {
Mail mail = new Mail();// 邮件模板对象
SendMail sender1 = new SendMail(mail);
Thread tSender1 = new Thread(sender1, "发送线程1");
SendMail sender2 = new SendMail(mail);
Thread tSender2 = new Thread(sender2, "发送线程2");
SendMail sender3 = new SendMail(mail);
Thread tSender3 = new Thread(sender3, "发送线程3");
tSender1.start();
tSender2.start();
tSender3.start();
}
}
大家可以将mailClone换成mail试一下就会发现,称呼和邮件内容的称呼可能就会不一致。这里顺便提一下,java 里的clone是浅拷贝,所谓浅拷贝是不对对象中的引用类型拷贝,只会对基本数据类型进行拷贝。浅拷贝对应的是深拷贝(即引用类型也可拷贝),大家可以通过重写clone方法实现自己对象的深拷贝。