Java 線程學習總結

1. 線程使用run()和start()有什麼區別
直接使用run(),是將線程對象當做普通對象來處理,那麼run()相當於執行了一個普通對象實例的普通方法。線程只有主線程一個。
而start(),則會啓動一個新的線程。
public class TestThread implements Runnable {
        public void run() {
          System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
        }
        
        public static void main(String[] args) {
          Thread t1 = new Thread(new TestThread());
          Thread t2 = new Thread(new TestThread());
          Thread t3 = new Thread(new TestThread());
          t1.run();
          t2.run();
          t3.run();
          System.out.println(Thread.currentThread().getName());
        }
}
 
執行結果:
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
 
使用start()方法
public class TestThread implements Runnable {
        public void run() {
          System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getThreadGroup());
        }
        
        public static void main(String[] args) {
          Thread t1 = new Thread(new TestThread());
          Thread t2 = new Thread(new TestThread());
          Thread t3 = new Thread(new TestThread());
          t1.start();
          t2.start();
          t3.start();
          System.out.println(Thread.currentThread().getName());
        }
}
執行結果:
Thread[Thread-0,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
main
Thread[Thread-2,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
Thread[Thread-1,5,main]:java.lang.ThreadGroup[name=main,maxpri=10]
注意,打印語句的順序有可能發生變化。
 
2 sleep()方法與wait()方法的區別
sleep()方法是Thread類的方法,而wait()方法則是Object類的方法。某個線程調用sleep()方法是休眠一定時間,在這段時間裏,並不釋放已獲得的對象鎖。而wait()方法則阻塞當前線程,並釋放已獲得的對象鎖。(爲什麼wait()方法一定要釋放對象鎖,因爲wait()方法有可能長時間不被喚醒,如果它一直佔用對象鎖,那就麻煩大了)。
實例說明sleep()一直佔用對象鎖。
public class BankAccount {
        private long balance;
        
        public synchronized void setBalance(long balance) {
          this.balance = balance;
        }
        
        public synchronized long getBalance() {
          System.out.println("balance .... " + this.balance);
          return balance;
        }
        
  public synchronized void save() {
    try {
      Thread.currentThread().sleep(1000);
    } catch(InterruptedException e) {
        
    }
    this.balance = this.balance + 1000;
    System.out.println("save 1000");
  }        
    
  public synchronized void draw() {
    this.balance = this.balance - 1000;
    System.out.println("draw 1000");
  }
}
 
再創建一個線程類進行測試
public class OperateThread implements Runnable {
  private BankAccount account;
  private String operating;

  public void run() {
    operate();
  }

  public void operate() {
    if (operating.equals("save")) {
      this.account.save();
    } else
      this.account.draw();
    }
  }

  public OperateThread(BankAccount account, String operating) {
    this.account = account;
    this.operating = operating;
  }

  public static void main(String[] args) {
    BankAccount account = new BankAccount();
    Thread save = new Thread(new OperateThread(account, "save"));
    Thread draw = new Thread(new OperateThread(account, "draw"));
    save.start();
    draw.start();
  }
}
 
輸出結果如下所示:
save 1000
draw 1000
 
可見,save()方法sleep()了1000ms,draw()必須等待save()執行完畢。
將draw()方法的synchronized修飾詞去掉。
public class BankAccount {
        private long balance;
        
        public synchronized void setBalance(long balance) {
          this.balance = balance;
        }
        
        public synchronized long getBalance() {
          System.out.println("balance .... " + this.balance);
          return balance;
        }
        
  public synchronized void save() {
    try {
      Thread.currentThread().sleep(1000);
    } catch(InterruptedException e) {
        
    }
    this.balance = this.balance + 1000;
    System.out.println("save 1000");
  }        
    
  public void draw() {
    this.balance = this.balance - 1000;
    System.out.println("draw 1000");
  }
}
再次執行,輸出結果如下,
draw 1000
save 1000
此時draw()不會等待save()執行完畢。
 
使用wait()來改寫BankAccount類。
public class BankAccount {
        private long balance;
        
        public synchronized void setBalance(long balance) {
          this.balance = balance;
        }
        
        public synchronized long getBalance() {
          System.out.println("balance .... " + this.balance);
          return balance;
        }
        
  public synchronized void save() {
    try {
      wait();
    } catch(InterruptedException e) {
        
    }
    this.balance = this.balance + 1000;
    System.out.println("save 1000");
  }        
    
  public synchronized void draw() {
    this.balance = this.balance - 1000;
    System.out.println("draw 1000");
    notifyAll();
  }
}
輸出結果如下所示,
draw 1000
save 1000
可見,save()方法阻塞了進程,但是draw()仍然可以執行。
 
3,什麼是對象監視器。
Java中內置了對併發訪問的支持機制,每個對象都有一個監視器,在同一時刻,只允許一個線程獲得監視器,並訪問對象的同步方法。其他線程必須等待對象監視器被釋放才能訪問對象的同步方法,但是可以隨時訪問其它非同步方法。
這裏的對象是指,創建線程時,所使用的target對象。
例如,Thread t = new Thread(target)中的target。
Thread如何獲得對象監視器呢?Thread通過調用對象的同步方法即可獲得對象監視器。
所以,一旦某個Thread調用了對象的synchronized方法,那麼其他線程將無法調用該對象的任何synchronized方法。
 
4 什麼是守護進程
守護進程也是進程,爲什麼叫它守護進程呢?它並不是守護某個其他的進程或對象。這裏的守護跟程序執行完畢,JVM退出有關。
JVM退出有兩種方式,一是所有進程都執行完畢,JVM自動退出;二是執行System.exit(0)直接退出。
在第一種情況下,所有進程執行完畢是指,所有用戶進程執行完畢。當然,線程分用戶線程和守護線程兩類。用戶線程會限制JVM,不能在用戶線程執行完畢之前正常退出。而守護線程則不會限制JVM。
舉例來說,
public class TestThread implements Runnable {
  public void run() {
    // System.out.println(Thread.currentThread() + ":" +
    // Thread.currentThread().getThreadGroup());
    for (int i = 1; i < 11; i++) {
      try {
        Thread.currentThread().sleep(15);
      } catch (InterruptedException e) {

      }
      System.out.println("Current Time ........................... = "
          + i);
    }
  }

  public static void main(String[] args) {
    Thread t1 = new Thread(new TestThread());
    // Thread t2 = new Thread(new TestThread());
    // Thread t3 = new Thread(new TestThread());
    // t1.setDaemon(true);
    t1.start();
    // t2.start();
    // t3.start();
    System.out.println(Thread.currentThread().getName());
  }
}
t1作爲一個用戶線程,只有當其執行完畢,JVM纔會退出。
輸出結果如下所示:
main
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
Current Time ........................... = 4
Current Time ........................... = 5
Current Time ........................... = 6
Current Time ........................... = 7
Current Time ........................... = 8
Current Time ........................... = 9
Current Time ........................... = 10
 
將t1設置爲守護線程時,代碼如下所示:
public class TestThread implements Runnable {
  public void run() {
    // System.out.println(Thread.currentThread() + ":" +
    // Thread.currentThread().getThreadGroup());
    for (int i = 1; i < 11; i++) {
      try {
        Thread.currentThread().sleep(15);
      } catch (InterruptedException e) {

      }
      System.out.println("Current Time ........................... = "
          + i);
    }
  }

  public static void main(String[] args) {
    Thread t1 = new Thread(new TestThread());
    // Thread t2 = new Thread(new TestThread());
    // Thread t3 = new Thread(new TestThread());
    t1.setDaemon(true);
    t1.start();
    // t2.start();
    // t3.start();
    System.out.println(Thread.currentThread().getName());
  }
}
此時的輸出結果如下所示:
main
Current Time ........................... = 1
Current Time ........................... = 2
Current Time ........................... = 3
可見,輸出只打印了10條語句中的3條。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章