java之涉足線程

---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------

進程:直譯就是正在進行中的程序。

線程:就是進程中一個負責程序執行的控制單元 

      一個進程可以有多執行路徑,稱之爲多線程

      一個進程至少有一個線程。

多線程的好處: 解決了部分同時運行的問題

多線程的弊端: 線程太多會倒效率的降低

其實應用程序的執行都是cpu在做着快速的切換完成的 這個切換是隨機的

如果創建一個線程?

方式一 繼續Thread

步驟 :1 定義一個類繼續Thread類 

       2 覆蓋Thread類中的run方法。

       3 直接創建Thread的子類對象創建線程。

例如:

class Demo extends Thread
{
 private String name;
 Demo(String name)
 {
  super(name);
  // this.name = name;
 }
 public void run()
 {
  for (int x = 0; x < 10; x++)
  {
  // for(int y=-9999999; y<999999999; y++){}
   System.out.println(name + "....x=" + x + ".....name="
    + Thread.currentThread().getName());
  }
 }
}
class ThreadDemo2
{
 public static void main(String[] args)
 {
  Thread t1 = new Thread();
  Demo d1 = new Demo("旺財");
  Demo d2 = new Demo("xiaoqiang");
  d1.start();// 開啓線程,調用run方法。
  d2.start();
  System.out.println("over...." + Thread.currentThread().getName());
 }
}

jvm創建的主線程的任務都是定義在了主函數中。

run()方法中定義就是線程要運行的人物代碼。

創建時就明確了名稱的定義

Thread 通過getName()來獲取線程的名稱。Thread編號從0開始。

主線程的名字就是main

創建線程的第二種方式:實現Runnable接口 

定義類實現Runnable接口  

覆蓋接口中的run方法,將線程的人物代碼封裝在run()中

3通過Thread類創建線程對象,並將Runnable接口的子類對象作爲構造函數的參數進行傳遞

例如:

class Bank
{
 private int sum;
 // private Object obj = new Object();
 public synchronized void add(int num)// 同步函數
 {
  // synchronized(obj)
  // {
  sum = sum + num;
  // -->
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
  }
  System.out.println("sum=" + sum);
  // }
 }
}
class Cus implements Runnable
{
 private Bank b = new Bank();
 public void run()
 {
  for (int x = 0; x < 3; x++)
  {
   b.add(100);
  }
 }
}
class BankDemo
{
 public static void main(String[] args)
 {
  Cus c = new Cus();
  Thread t1 = new Thread(c);
  Thread t2 = new Thread(c);
  t1.start();
  t2.start();
 }
}

爲什麼這樣做?因爲線程的任務都封裝在Runnable接口子類對象中的方法中,所以要在線程對象創建時就必須明確要運行的任務。

調用線程對象的start方法開啓線程。

Runnable她的出現僅僅是將線程的任務進行了對象的封裝。

實現了Runnable接口的好處:

 1 將線程的任務從線程的子類中分離出來,進行了單獨的封裝

   按照了面向對象的思想將任務封裝成對象

 2 避免了java單繼承的侷限性。

創建線程的第二種方式最常用。

多次啓動一個線程是非法的。

線程安全問題產生的原因

1 多個線程在操作共享數據

2 操作共享數據的線程代碼有多條。

當一個線程在執行操作共享數據的多條代碼過程中,其他線程參與了運算 

就會導致線程安全問題的產生。

解決思路:

就是將多條操作共享數據的線程代碼封裝起來,當有線程在執行這些代碼的時候,

其他線程是不可以參與運算的

必須要當前線程把這些代碼都執行完畢後,其他線程纔可以參與運算。

java中,用同步代碼塊就是可以解決這個問題

同步代碼塊的格式

synchronized(對象){

    需要同步的代碼:

}

同步的好處就是: 解決了線程安全的問題

      弊端就是:相對降低了效率,因爲同步的外線程的都會判斷同步鎖。

同步的前提:必須有多個線程並使用同一個鎖。

同步函數和同步代碼的鎖是this

同步函數和同步代碼塊的區別:

同步代碼塊的鎖是任意對象 

同步函數的鎖是固定的 this

建議使用同步代碼。

靜態的同步函數使用的鎖是 該函數所屬字節碼文件對象, 可以用getClass方法獲取,也可以用當前類名.class表示。

//懶漢式   面試經常面試到的

class single{

  private static finall Single s=null

  privat single{

    }

  public static Single getInstance(){

      ifs==null{ //第一次判斷是爲了提高效率 

         synchronizedSingleclass{//解決安全隱患。

             ifs==null{

                  s=new Single();

                }

            }

       }

       return s

 }

}

線程常見的問題之一:死鎖。

同步的嵌套。

/*

死鎖:常見情景之一:同步的嵌套。

*/

class Ticket implements Runnable
{
 private int num = 100;
 Object obj = new Object();
 boolean flag = true;
 public void run()
 {
  if (flag)
   while (true)
   {
    synchronized (obj)
    {
     show();
    }
   }
  else
   while (true)
    this.show();
 }
 public synchronized void show()
 {
  synchronized (obj)
  {
   if (num > 0)
   {
    try {
     Thread.sleep(10);
    } catch (InterruptedException e) {
     System.out.println(Thread.currentThread().getName()
       + ".....sale...." + num--);
    }
   }
  }
 }
 class DeadLockDemo
 {
  public static void main(String[] args)
  {
   Ticket t = new Ticket();
   // System.out.println("t:"+t);
   Thread t1 = new Thread(t);
   Thread t2 = new Thread(t);
   t1.start();
   try {
    Thread.sleep(10);
   } catch (InterruptedException e) {
   }
   t.flag = false;
   t2.start();
  }
 }
}

 

等待 喚醒機制

涉及的方法。

1 wait() 讓線程處於凍結狀態,被wait的線程會被存儲到線程池中。

2 notify()喚醒線程池中的一個任意線程

3 notifyAll()喚醒線程池中的所有線程

這些方法都必須定義在同步中

因爲這些方法是用於操作線程狀態的方法

必須要明確到底操作的是哪個鎖上的線程。

爲什麼操作線程的方法wait notify notifyAll定義在了object類中?

因爲這些方法是監視器的方法。監視器其實就是鎖。

jdk 1.5出現了 lock 替代了synchronized

jdk 1.5出現以後將同步和鎖封裝成了對象,並將操作的隱式定義到了該對象中,將隱式動作變成了顯示動作。

lock接口:出現替代了同步代碼塊或者同步函數。將同步代碼的隱式鎖操作變成了顯示鎖操作。

 同時更爲靈活可以一個鎖上加上多組監視器

 lock():獲取鎖

 unlock():釋放鎖,通常需要定義finally代碼塊中。

Condition接口: 出行替代了Object中的wait notify notifyAll 方法。

             將這些監視器方法單獨進行了封裝,變成了Condition監視器對象。

             可以任意鎖緊組合。

await();

signal();

signalAll();

wait sleep 區別

1wait可以指定時間也可以不指定。

  sleep必須要指定時間

在同步中時,多cpu的執行權和鎖的處理不同

 wait:釋放行權,釋放鎖

 sleep:釋放執行權,不釋放鎖。

我的總結:Java線程是Java語言中一個非常重要的部分通過使用Java5線程新特徵的API,可以很容易的做出複雜的多線程程序。

 

 

---------------------- (科技新時代)申請入駐搜狐公衆平臺,特此聲明----------------------

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章