Callable 接口与Runnable接口类似可实现多线程的创建,但与Runnable不同的是,其线程方法call()有返回值并可抛出异常(Runnable 不会返回结果,并且无法抛出经过检查的异常)。另外Callable创建多线程依赖于线程池。
通过API查询,可以看到,Callable<V>是带泛型的,其泛型就是call方法返回值类型。
以下通过创建商品“秒杀”多线程FlashSale,实例讲解Callable 实现多线程的步骤:
1. 创建线程类FlashSale,实现Callable接口,重写call方法。
2.创建FlashSale线程实例binge,craze。
3.创建线程池对象实例shoppingPool
4.通过线程池实例shoppingPool的submit方法执行binge,craze。
package net.mosang.callabledemo;
import java.util.concurrent.Callable;
/**
* FlashSale线程类
* @author Heiry
* 重写不带任何参数的 call方法,返回String类型的抢购结果提示
*/
public class FlashSale implements Callable<String>{
private String goodsName;
@Override
public String call() throws Exception {
if(goodsName.equals("Mac电脑")) {
return "抢到了苹果电脑";
}else if (goodsName.equals("Mi手机")) {
return "抢到了小米手机";
}
else {
return "什么也没抢到";
}
}
public FlashSale(String goodsName) {
super();
this.goodsName = goodsName;
}
}
package net.mosang.callabledemo;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
*
* @author Heiry
*
*/
public class Shopping {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FlashSale binge = new FlashSale("Mac电脑"); //创建线程实例binge
FlashSale craze = new FlashSale("Mi手机");//创建线程实例craze
ExecutorService shoppingPool = Executors.newFixedThreadPool(2);
Future<String> s1 = shoppingPool.submit(binge);
Future<String> s2 = shoppingPool.submit(craze);
System.out.println(s1.get());
System.out.println(s2.get());
}
}
输出结果
抢到了苹果电脑 抢到了小米手机
可见,相比继承Thread与实现Runable接口方式实现多线程,Callable更方便地得到多线程的返回值并进行异常处理。另外,Callable依赖于线程池,通过此方式创建多线程,步骤繁琐,更适合处理高并发。


适配器模式包含以下主要角色。
1. 已经存在的、具备完备功能的类 Adaptee(适配者)。
2. 当前系统业务所期待的接口(Target),但与现Adaptee不兼容,它可以是抽象类或接口。
3. 适配器类(Adapter)。通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
实例:
现有一个两孔插座,能对外提供220v稳定电压,但现业务需要,需要提供三孔插座,同样输出220v稳定电压,这就需要一个适配器来进行转换。

代码结构及详细:
package net.mosang.adapter;
public interface ThreeSocket {
public void threeSocket220v();//期望三孔输出220v电压的插线板
}
package net.mosang.adapter;
public class TwoSocket {
public void twoSocket220v() {//现有两孔可输出220v电压的插线板
System.out.println("220v电压持续输出中。。。。。");
}
}
package net.mosang.adapter;
public class Adaptor implements ThreeSocket {
private TwoSocket two;
@Override
public void threeSocket220v() { //对外提供了三孔220v电压功能线板
two.twoSocket220v();//实际依然是经过两孔输出
}
public TwoSocket getTwo() {
return two;
}
public void setTwo(TwoSocket two) {
this.two = two;
}
public Adaptor(TwoSocket two) {
super();
this.two = two;
}
}
package net.mosang.adapter;
public class Client {
public static void main(String[] args) {
TwoSocket two = new TwoSocket();
Adaptor adaptor = new Adaptor(two);
adaptor.threeSocket220v(); // 输出"220v电压持续输出中。。。。。"
}
}
UML关系图:


用一个已经创建的实例作为原型,克隆(clone)该原型对象来创建一个和原型相同或相似的新对象,免去创建对象的复杂过程和细节。原型模式分浅拷贝与深拷贝两种。
浅拷贝实现方式:
1.原型类实现CLoneable接口
2.拷贝对象通过原型的clone方法获得新的实例
深拷贝实现方式:
1.原型类实现CLoneable接口
2.原型类重写clone方法,并在克隆对象同时也克隆响应的引用类型成员变量。
————————————–
以下通过国宝熊猫的克隆来理解浅拷贝与深拷贝:
熊猫类包含两个成员属性:熊猫名字与饲养员。熊猫名字为普通字符串对象,饲养员为引用对象。以下分别通过浅拷贝和深拷贝两种方式克隆熊猫对象:
浅拷贝方式:
package net.mosang.prototype;
import java.util.Date;
/**
*
* @author heiry
*
*/
public class Panda implements Cloneable {
private String name;
private Feeder feeder;
//重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Panda panda = (Panda) super.clone();
return panda;
}
//setter、getter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Feeder getFeeder() {
return feeder;
}
public void setFeeder(Feeder feeder) {
this.feeder = feeder;
}
//构造方法
public Panda(String name, Feeder feeder) {
super();
this.name = name;
this.feeder = feeder;
}
}
package net.mosang.prototype;
public class Feeder {
public String name;
public void feed() {
System.out.println("feed panda....");
}
public Feeder(String name) {
super();
this.name = name;
}
}
package net.mosang.prototype;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Feeder feeder = new Feed犀利士
er("张大胖");
Panda p1 = new Panda("pangpang",feeder);
Panda p2 = (Panda) p1.clone();
System.out.println(p1);
System.out.println(p2);
feeder.name = "张小胖";
System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
}
}
运行结果:
net.mosang.prototype.Panda@15db9742 net.mosang.prototype.Panda@6d06d69c p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖 p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张小胖
可见浅拷贝方式,虽然获得了一个与原型对象一样的新对象,但是对于引用类型成员变量feeder,拷贝的是地址而不是对象本身,换句话说,两个对象的feeder指向的是同一个Feeder对象。
深拷贝方式:
重点在于重写原型类的clone方法:
package net.mosang.prototype;
/**
*
* @author heiry
*
*/
public class Panda implements Cloneable{
private String name;
private Feeder feeder;
//重写clone方法,并将引用成员变量feeder同时克隆
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Panda panda = (Panda) obj ;
panda.feeder = (Feeder)this.feeder.clone();
return panda;
}
//setter、getter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Feeder getFeeder() {
return feeder;
}
public void setFeeder(Feeder feeder) {
this.feeder = feeder;
}
//构造方法
public Panda(String name, Feeder feeder) {
super();
this.name = name;
this.feeder = feeder;
}
}
package net.mosang.prototype;
public class Feeder implements Cloneable{
public String name;
public void feed() {
System.out.println("feed panda....");
}
public Feeder(String name) {
super();
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package net.mosang.prototype;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Feeder feeder = new Feeder("张大胖");
Panda p1 = new Panda("pangpang",feeder);
Panda p2 = (Panda) p1.clone();
System.out.println(p1);
System.out.println(p2);
feeder.name = "张小胖";
System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
}
}
运行结果:
net.mosang.prototype.Panda@15db9742 net.mosang.prototype.Panda@6d06d69c p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖 p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张大胖
可以看到,深拷贝的引用类型成员变量也是各自独立的。