多线程之Thread和Runable选择及原理(二)

模拟排队等号例子

Thread:

public class TicketWindows extends Thread{
    private final String name;
    private final int MAX = 6;
    private int index = 1;

    public TicketWindows(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        while(index <= MAX){
            System.out.println("柜台"+name+"出票:" + index++);
        }

    }


    public static void main(String[] args) {
        TicketWindows ticketWindows1 = new TicketWindows("一");
        ticketWindows1.start();

        TicketWindows ticketWindows2 = new TicketWindows("二");
        ticketWindows2.start();

        TicketWindows ticketWindows3 = new TicketWindows("三");
        ticketWindows3.start();
    }
}

上述代码从打印结果可以看出:每个窗口都出票了6次,而不是共同出票6次。
因为创建了3个实例,每个实例的index都是独立的。可以在index前面加static避免这种情况,下面介绍通过Runable解决。


Runable:

public class TicketWindowsRunable implements Runnable{
    private String name;
    private final static int MAX = 6;
    private  int index = 1;

    @Override
    public void run() {

        while (index <= MAX) {
            System.out.println(Thread.currentThread().getName() + "号码是" + index++);
        }
    }

    public static void main(String[] args) {
        final TicketWindowsRunable ticketWindowsRunable = new TicketWindowsRunable();
        Thread thread1 = new Thread(ticketWindowsRunable, "1");
        Thread thread2 = new Thread(ticketWindowsRunable, "2");
        Thread thread3 = new Thread(ticketWindowsRunable, "3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

3个窗口共同发票6次。(暂不考虑线程安全问题)


Runnable和Thread区别

实际开发中我们通常采用Runnable接口来实现多线程。因为实现Runnable接口比继承Thread类有如下好处:
- 避免继承的局限,一个类可以继承多个接口,但是类只能继承一个类。
- Runnable接口实现的线程便于资源共享。而通过Thread类实现,各自线程的资源是独立的,不方便共享。上面例子可以看出线程ticketWindows1,2,3各卖了6张票,而线程thread1,2,3共卖6张票.

 使用Runnable对象时,Runnable定义的子类没有start()方法,只有Thread类中才有,观察Thread类,有一个构造方法public Thread(Runnable target),此构造方法接受Runanble的子类实例,也就是说可以通过Thread类来启动Runnable实现多线程。这种模式和**策略模式**相识,下面讲解策略模式。


策略模式

  • 创建接口CalculatorStrategy
public interface CalculatorStrategy {
    double calculate(double salary, double bonus);

}
  • 实现接口的类SimpleCalculatorStrategy
public class SimpleCalculatorStrategy implements CalculatorStrategy {

    private final static double SALARY_RATE = 0.1;
    private final static double BONUS_RATE = 0.15;

    @Override
    public double calculate(double salary, double bonus) {
        return salary * SALARY_RATE + bonus * BONUS_RATE;
    }
}
  • 类TaxCalaculator
public class TaxCalaculator {
    private final double salary;
    private final double bonus;
    private final CalculatorStrategy calculatorStrategy;
    public TaxCalaculator(double salary, double bonus,CalculatorStrategy calculatorStrategy) {
        this.salary = salary;
        this.bonus = bonus;
        this.calculatorStrategy = calculatorStrategy;
    }

    //执行实现接口得方法
    protected double calcTax(){
        return calculatorStrategy.calculate(salary,bonus);
    }

    public double calculate(){
        return this.calcTax();
    }
}
  • 测试mian
public static void main(String[] args) {

       TaxCalaculator calculator = new TaxCalaculator(10000d, 2000d,new SimpleCalculatorStrategy());
        System.out.println(calculator.calculate());
    }

如此费劲到底有什么好处呢? 如果下次计算公式变了,只要重写个类去实现接口,重写方法就行了,不影响之前的代码逻辑。比如重写写类A实现接口,调用的时候TaxCalaculator calculator = new TaxCalaculator(10000d, 2000d,new A());就ok了,是不是很Runable很相识。

注意:在java8中有更好的方法,避免了单独写类去实现接口。如:TaxCalaculator calculator = new TaxCalaculator(10000d, 2000d,(s,b)->s * 0.1 + b * 0.15);

总结:结合上一篇,我们知道了Runable和Thread利用 模板模式和 策略模式,通过学习多线程间接学习了两种设计模式,很有成就感,有木有?????

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值