3). Thread子类的run方法抽取----优化I (1). 2)中对Thread类或者其子类修正之后存在的缺点 [1]. 缺点I:增加了Thread类或者其子类对锁对象的访问的难度 由于共享数据 (线程需要共同操作的对象和锁对象) 已经被封装到自定义的SynClassI中,所以如果想在Thread 类或者其子类中使用锁对象进行代码块的同步需要通过Thread子类的SynClassI类型的成员变量synClassObj进行调用。由于此时锁对象objLock2在SynClassI中是以私有成员的形式存在的,所以要为这个私有成员增加Setter和Getter以方便外部的run方法对这个锁对象进行访问。 [2]. 缺点II:增加了Thread类或者其子类对共享操作数据的访问的难度 同样道理:Thread类或者子类想访问被封装到SynClassI类中的需要被多个线程同时操作的ticketNum的时候,也是不能直接在run方法中直接进行访问。 [3]. 通过图的形式表现出第一次修正存在缺点【下图2】
(2). Thread子类+ 自定义SynClassI类的优化 ----抽取run()方法 [1]. 优化I:将Thread类或者子类中的run方法也移植到自定义类SynClassI类中 这样在SynClassI中不用提供共享数据的Setter和Getter,直接在SynClass中的run方法中直接访问需要的共享数据。 [2]. 优化II:在Thread类或者子类中直接通过自定义类SynClass类的synClassObj对象直接调用SynClassObj封装好的run方法即可。这样无论是多线程运行的时候需要什么种类的共享数据,都直接在自定义类SynClass中的run方法进行操作,Thread类或者子类只管调用自定义类的run方法就可以了。 【优点】为自定义SynClass类增加了run方法实际上是格式化了Thread类的代码 (3). 取run()方法后的示例代码 ----优化I示例代码 [1]. 优化之后的自定义类的代码SynClassII class SynClassII{ private int tickNum =10; private Object objLock2 =new Object(); //自定义类SynClassII增加了run方法 ----格式化了Thread类或者子类中的run的代码 public void run(){ while(true){ synchronized(objLock2){ if(tickNum <=0) break; try { Thread.sleep(10); }catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread()+". sale: ticket"+ tickNum--); } } } } [2]. 优化之后的Thread子类的代码 TicketV class TicketV extends Thread{ private SynClassII synClassObj; public TicketV(){} public TicketV(SynClassII synClassObj){ super(); this.synClassObj =synClassObj; } public void run(){ //防止synClassObj没有被赋值而抛出空指针异常 //----无论用户自定义的代码是什么样的,都是调用自定义类对象的run方法 //---- 非常固定 --- 格式化 if(this.synClassObj !=null){ this.synClassObj.run(); } } } 【注意】 这里进行if判断的原因就是保证在synClassObj是空的情况下不会抛出控制异常。 [3]. 优化之后的测试代码 public class TickeDemoCompareVI{ public static void main(String[] args){ SynClassIIsynClassObj =new SynClassII(); Threadt1 =new TicketV(synClassObj); Threadt2 =new TicketV(synClassObj); Threadt3 =new TicketV(synClassObj); Threadt4 =new TicketV(synClassObj); t1.start(); t2.start(); t3.start(); t4.start(); } } [4]. 优化之后的运行结果【下图3】
|