Scala隱式轉換理論及進階實踐-Coding技術進階實戰

開心雲技術社群發表於2019-01-10

秦凱新技術社群推出的《Coding技術進階實戰》系列即將上線,包含語言類精深的用法和技巧,涵蓋 python,Java,Scala,Tensorflow等主流大資料和深度學習技術基礎,敬請期待。為什麼我會寫這樣一個系列,來源於被一位容器雲專家問到如何實現一個執行緒池時,讓我頓感以前研究的Java併發控制相關的理論以及多執行緒併發設計模式忘得九霄雲外,鑑於此,氣憤難平,決定展示個人程式設計魅力。

版權宣告:本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:1120746959@qq.com,如有任何技術交流,可隨時聯絡。

1 Scala 隱式轉換函式深入實踐

1.1 隱式轉換

要實現隱式轉換,只要程式可見的範圍內定義隱式轉換函式即可。Scala會自動使用隱式轉換函式。隱式轉換函式與普通函式唯一的語法區別就是,要以implicit開頭,而且最好要定義函式返回型別。

案例:特殊售票視窗(只接受特殊人群,比如學生、老人等)
詳解:當呼叫buySpecialTicket函式時,傳入引數Student不對照時,會進行隱式轉換為SpecialPerson

class SpecialPerson(val name: String)
class Student(val name: String)
class Older(val name: String)

implicit def object2SpecialPerson (obj: Object): SpecialPerson = {
  if (obj.getClass == classOf[Student]) { val stu = obj.asInstanceOf[Student]; new SpecialPerson(stu.name) }
  else if (obj.getClass == classOf[Older]) { val older = obj.asInstanceOf[Older]; new SpecialPerson(older.name) }
  else Nil
}

var ticketNumber = 0
def buySpecialTicket(p: SpecialPerson) = {
  ticketNumber += 1
  "T-" + ticketNumber
}

scala> var stu =new Student("qinkaixin")
stu: Student = Student@2f6bbeb0

scala> buySpecialTicket(stu)
res0: String = T-1
複製程式碼

1.2 使用隱式轉換加強現有型別

隱式轉換非常強大的一個功能,就是可以在不知不覺中加強現有型別的功能。也就是說,可以為某個類定義一個加強版的類,並定義互相之間的隱式轉換,從而讓源類在使用加強版的方法時,由Scala自動進行隱式轉換為加強類,然後再呼叫該方法。

    案例:超人變身
    詳解:當呼叫不屬於Man的方法時,指直接呼叫隱式轉換函式man2superman,並呼叫emitLaser方法
    
    class Man(val name: String)
    class Superman(val name: String) {
      def emitLaser = println("emit a laster!")
    }
    
    implicit def man2superman(man: Man): Superman = new Superman(man.name)
    
    val leo = new Man("leo")
    leo.emitLaser
複製程式碼

1.3 隱式引數

所謂的隱式引數,指的是在函式或者方法中,定義一個用implicit修飾的引數,此時Scala會嘗試找到一個指定型別的,用implicit修飾的物件,即隱式值,並注入引數。

Scala會在兩個範圍內查詢:

  • 一種是當前作用域內可見的val或var定義的隱式變數;

  • 一種是隱式引數型別的伴生物件內的隱式值

      案例:考試簽到
      詳解:簽到筆作為隱式引數,注入到函式中,從而可以使用隱式引數物件的屬性。
      
      class SignPen {
        def write(content: String) = println(content)
      }
      implicit val signPen = new SignPen
      
      def signForExam(name: String) (implicit signPen: SignPen) {
        signPen.write(name + " come to exam in time.")
      }
    複製程式碼

2 Java 手寫執行緒池

2.1 PThread 實現

    public class PThread extends Thread 
    {
    
        private ThreadPool pool;
        private Runnable target;   
        private boolean isShutDown = false;
        private boolean isIdle = false;
        
        public PThread(Runnable target, String name, ThreadPool pool)
        {
            super(name);
            this.pool = pool;
            this.target = target;
        }
        
        public Runnable getTarget() 
        {
            return target;
        }
        
        public boolean isIdle() 
        {
            return isIdle;
        }
        public void run() 
        {
            while (!isShutDown) 
            {  
                isIdle = false;
                if (target != null) 
                {
                    target.run();  
                }
                isIdle = true;
                try 
                {
                    pool.repool(this);
                    synchronized (this) 
                    {
                        wait();
                    }
                }
                catch (InterruptedException ie)
                {
                }
                isIdle = false;
            }
        }
        
        
        public synchronized void setTarget(java.lang.Runnable newTarget) 
        {
            target = newTarget; 
            notifyAll();       
        }
        
        public synchronized void shutDown()
        {
            isShutDown = true;
            notifyAll();
        }
    }
複製程式碼

2.2 ThreadPool 實現

    import java.util.List;
    import java.util.Vector;
    
    public class ThreadPool 
    {
        private static ThreadPool instance = null;
    

        private List<PThread> idleThreads;
        private int threadCounter;
        private boolean isShutDown = false;
        
        private ThreadPool() 
        {       
            this.idleThreads = new Vector(5);
            threadCounter = 0;
        }
        
        public int getCreatedThreadsCount() {
            return threadCounter;
        }
        

        public synchronized static ThreadPool getInstance() {
            if (instance == null)
                instance = new ThreadPool();
            return instance;
        }
       
        protected synchronized void repool(PThread repoolingThread)
        {
            if (!isShutDown) 
            {
                idleThreads.add(repoolingThread);
            }
            else 
            {
                repoolingThread.shutDown();
            }
        }
            
        public synchronized void shutdown()
        {
           isShutDown = true;
           for (int threadIndex = 0; threadIndex < idleThreads.size(); threadIndex++)
           {
                 PThread idleThread = (PThread) idleThreads.get(threadIndex);
                 idleThread.shutDown();
           }
        }
        

        public synchronized void start(Runnable target)
        {
            PThread thread = null; 

            if (idleThreads.size() > 0) 
            {
                int lastIndex = idleThreads.size() - 1;
                thread = (PThread) idleThreads.get(lastIndex);
                idleThreads.remove(lastIndex);
                thread.setTarget(target);
            }

            else 
            { 
                threadCounter++;
                thread = new PThread(target, "PThread #" + threadCounter, this);
                thread.start();
            }
        }
    }
複製程式碼

2.3 ThreadPool 測試

	public void testThreadPool() throws InterruptedException {
		long starttime=System.currentTimeMillis();
		for(int i=0;i<1000;i++){
			ThreadPool.getInstance().start(new MyThread("testThreadPool"+Integer.toString(i)));
		}
		
		long endtime=System.currentTimeMillis();
		System.out.println("testThreadPool"+": "+(endtime-starttime));
		System.out.println("getCreatedThreadsCount:"+ThreadPool.getInstance().getCreatedThreadsCount());
		Thread.sleep(1000);
	}
複製程式碼

3 未完待續

相關文章