Java多線程理解1

Java實現多線程的兩種方式分別是繼承Thread類和實現Runnable接口。


  1. 繼承Thread類
class MyThread extends Thread{
     @Override 
      public void run(){
      for(int i=0;i<7;i++){
       System.out.println("MyThread:"+Thread.currentThread().getName()+" 次數:"+i);
      }
     }
}
  1. 實現Runnable接口
class MyTask implements Runnable{
     @Override
     public void run(){
      for(int i=0;i<7;i++){
       System.out.println("MyTask:"+Thread.currentThread().getName()+" 次數:"+i);
      }
     }
    }
  1. 測試
public class Test {
  public static void main(String [] args){
      MyThread myThread = new MyThread();  
      myThread.start();  
      
      MyTask task = new MyTask();  
      Thread thread = new Thread(task);  
      thread.start();  
  }
}
MyThread:Thread-0 次數:0
MyThread:Thread-0 次數:1
MyThread:Thread-0 次數:2
MyThread:Thread-0 次數:3
MyThread:Thread-0 次數:4
MyThread:Thread-0 次數:5
MyTask:Thread-1 次數:0
MyThread:Thread-0 次數:6
MyTask:Thread-1 次數:1
MyTask:Thread-1 次數:2
MyTask:Thread-1 次數:3
MyTask:Thread-1 次數:4
MyTask:Thread-1 次數:5
MyTask:Thread-1 次數:6

程序會在不同的線程之間切換,每次的輸出結果并不相同。

關鍵點1:啟動線程使用start()方法,使用run()方法并不會啟動新線程。

public class Test {
  public static void main(String [] args){
      MyThread myThread = new MyThread();  
      myThread.run();  
      
      MyTask task = new MyTask();  
      Thread thread = new Thread(task);  
      thread.run();  
  }
}
MyThread:main 次數:0
MyThread:main 次數:1
MyThread:main 次數:2
MyThread:main 次數:3
MyThread:main 次數:4
MyThread:main 次數:5
MyThread:main 次數:6
MyTask:main 次數:0
MyTask:main 次數:1
MyTask:main 次數:2
MyTask:main 次數:3
MyTask:main 次數:4
MyTask:main 次數:5
MyTask:main 次數:6

start() : 通過調用start0()啟動一個新線程,新線程會執(zhí)行相應的run()方法。start()不能被重復調用。
run(): run()和普通的成員方法一樣可重復調用。單獨調用run()會在當前線程中執(zhí)行run(),并不會啟動新線程!

相關源碼:

public synchronized void start() {
        if (threadStatus != 0)  //start()方法不能被重復調用,否則會拋出異常
            throw new IllegalThreadStateException();
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);  //加入到線程組中
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
}
private native void start0();
關鍵點2:如何選擇Thread與Runnable.

其實Thread同樣實現了Runnable接口。

class Thread implements Runnable {
    //…
    public void run() {
        if (target != null) {
             target.run();
        }
    }
}

Thead的作用是啟動新的線程,而Runnable的作用表示執(zhí)行的任務。 (很好的體現了接口的原則:功能抽離;)
繼承Thead類表示我們需要一種特殊的Thead;而實現Runnable接口表示我們需要執(zhí)行某種任務;

Thread與Runnable的區(qū)別:

  1. 由于Java使用單繼承,多接口實現原則,所以通過Runnable接口實現多線程更具靈活性;
  2. Runnable對象可以被多個線程共享,更適合于多個線程處理同一資源的情況。
    (正確共享資源仍然需要加鎖)

示例(賣票問題):

  1. Thread
class MyThread extends Thread{
     private int tickets =5;  
     @Override  
     public void run() {  
      while (tickets>0) {  
                tickets--;
                System.out.println(Thread.currentThread().getName()+"賣了一張票,剩余票數:"+tickets);  
      }
}
}```
``` java
public class Test {
  public static void main(String [] args){
      MyThread myThread1 = new MyThread();  
      myThread1.start();  
       
      MyThread myThread2 = new MyThread();  
      myThread2.start();
  }
}
Thread-0賣了一張票,剩余票數:4
Thread-1賣了一張票,剩余票數:4
Thread-1賣了一張票,剩余票數:3
Thread-0賣了一張票,剩余票數:3
Thread-1賣了一張票,剩余票數:2
Thread-1賣了一張票,剩余票數:1
Thread-1賣了一張票,剩余票數:0
Thread-0賣了一張票,剩余票數:2
Thread-0賣了一張票,剩余票數:1
Thread-0賣了一張票,剩余票數:0
MyThread myThread2 = new MyThread();```
因為每次都創(chuàng)建了新的MyThread對象,內存中有兩份tickets,所以最后結果是賣了10張票;

1. Runnable
``` java
class MyRunnable implements Runnable{
     private int tickets =5;  
     @Override  
        public void run() {  
      while (tickets>0) {  
                tickets--;
                System.out.println(Thread.currentThread().getName()+"賣了一張票,剩余票數:"+tickets);  
           }
        }
}
public class Test {
  public static void main(String [] args){
     MyRunnable r = new MyRunnable();                
     Thread t1 = new Thread(r);    
     Thread t2 = new Thread(r);    
         
     t1.start();  
     t2.start();   
  }
}
Thread-0賣了一張票,剩余票數:4
Thread-1賣了一張票,剩余票數:3
Thread-0賣了一張票,剩余票數:2
Thread-0賣了一張票,剩余票數:1
Thread-0賣了一張票,剩余票數:0

MyRunnable對象只有一個,多線程共享同一對象,內存中只有1份tickets,賣票結果好像是正確的。

  1. synchronized加鎖
class MyRunnable implements Runnable{  
     
     private int tickets =5;  
        @Override  
        public void run() {  
         while (tickets>0) {  
                 try {  
                    Thread.sleep(100);  
                 } catch (InterruptedException e) {  
                     e.printStackTrace();  
                 }  
                 tickets--;
                 System.out.println(Thread.currentThread().getName()+"賣了一張票,剩余票數:"+tickets);  
            }  
         
        }  
    } 
Thread-0賣了一張票,剩余票數:4
Thread-1賣了一張票,剩余票數:4
Thread-1賣了一張票,剩余票數:3
Thread-0賣了一張票,剩余票數:2
Thread-0賣了一張票,剩余票數:0
Thread-1賣了一張票,剩余票數:0

顯然一共賣了6張票是不正確的,所以僅僅實現Runnable接口是無法進行資源共享的,如果需要共享還是需要加入synchronized關鍵字。

class MyRunnable implements Runnable{  
     
     private int tickets =5;  
        @Override  
        public void run() {  
         synchronized(this){
          while (tickets>0) {  
              try {  
                 Thread.sleep(100);  
              } catch (InterruptedException e) {  
                  e.printStackTrace();  
              }
                    tickets--;
                    System.out.println(Thread.currentThread().getName()+"賣了一張票,剩余票數:"+tickets);  
               }
         }
        }
    } 
Thread-0賣了一張票,剩余票數:4
Thread-0賣了一張票,剩余票數:3
Thread-0賣了一張票,剩余票數:2
Thread-0賣了一張票,剩余票數:1
Thread-0賣了一張票,剩余票數:0

[2015-08-20]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態(tài)及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,599評論 1 15
  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 3,110評論 1 18
  • 寫在前面的話: 這篇博客是我從這里“轉載”的,為什么轉載兩個字加“”呢?因為這絕不是簡單的復制粘貼,我花了五六個小...
    SmartSean閱讀 4,949評論 12 45
  • 1.簡介 對于操作系統(tǒng)而言同時可以允許多個程序, 而不同的程序是運行在一個進程中的。而線程(輕量級進程)是程序執(zhí)行...
    遇見技術閱讀 577評論 1 3
  • 子日:“弟子入則孝,出則弟,謹而信,泛愛眾而親仁。行有余力,則以學文?!笨鬃诱f:“青少年在家要孝敬父母,出外要尊...
    番茄媽閱讀 1,594評論 0 0

友情鏈接更多精彩內容