線程基礎

基本概念

基本:

  • 程序:一段靜態代碼,靜態對象
  • 進程:程序的一次執行過程
  • 線程:進程內部一個執行路徑
    比如:QQ正在運行是一個進程,同時聊天,視頻 兩個線程

何時需要多線程:

  • 程序需要執行多個任務
  • 執行等待的任務:如搜索時需要等待服務器返回響應,等待時間讓CPU做別的事情,先讓這個程序佔有的CPU做別的事情
  • 後臺運行程序:在主程序的執行過程中,中途有一行代碼開啓了線程,當其中的主程序運行的代碼和線程代碼並行執行,則主程序代碼和線程代碼就不想關了

多線程的建立與啓動

thread類(1)的:

  • 特性run() :線程體:代碼寫在run()方法中
  • start():用來啓動線程
  • 異步性:
    • 兩個線程各自保持前進的速度,你執行一次,我執行一次,接着我執行或者你執行,按照不同的順序推進

創建線程的兩種方式:

繼承Thread類:
  1. 創建一個子類繼承thread類

  2. 子類重寫run方法

  3. 創建子類對象:即創建了線程對象

  4. 調用對象的start方法

    public class Test {
    public static void main(String[] args) {
    //3步:創建多線程對象
    Thread t=new ThreadTest();
    t.start();
    //4步:調用start方法,啓動線程,調用run方法
    //threadTest.start();

     System.out.println("==========");
     System.out.println("=======5===");
     System.out.println("==========");
    

    }
    }

    /**創建一個子類繼承thread類

    • 多線程:繼承thread創建多線程
    • @author douer

    */
    public class ThreadTest extends Thread{
    //1.重寫thread
    @Override
    public void run() {
    System.out.println(“多線程運行代碼”);
    for(int i=0;i<3;i++) {
    System.out.println(i+6);
    System.out.println(i+6);
    }
    }
    }

實現接口Runnable:

  1. 定義子類實現runnable接口
    子類重寫run方法
    public class RunableTest implements Runnable {
    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+" : 多線程運行代碼");

  2. 在test中通過thread類含餐構造創建線程方法
    Thread t2=new Thread(new RunableTest(), “t-2 :”);//參數1是new一個實例,參數2是線程的名字

  3. start開啓線程

  • Thread.currentThread().getName():獲取當前線程的名稱

  • 線程名稱的作用:多線程運行時,可以明確是具體哪個的線程在運行
    實現接口:
    package ThreadTest;
    /**
    * 實現runnable接口的方式創建多線程
    * @author douer
    *
    */
    public class RunableTest implements Runnable {

    	@Override
    	public void run() {
    		System.out.println(Thread.currentThread().getName()+"  : 多線程運行代碼");
    		for(int i=0;i<3;i++) {
    			System.out.println(Thread.currentThread().getName()+"==="+i);
    		
    	    }
    	
       }
    }
    

    Test運行:
    package ThreadTest;

    public class Test {
        public static void main(String[] args) {
    	//第二種Runnable方
        	//2步:通過thread
             Thread t2=new Thread(new RunableTest(), "t-2  :");//參數1是new一個實例,參數2是線程的名字
             t2.start();
             //作用:多線程運行時,可以明確是具體哪個的線程在運行
             Thread t3=new Thread(new RunableTest(), "t-3  :");
             
             
             t3.start();
    	System.out.println("=======1==");
    	System.out.println("=======5===");
    	System.out.println("=======7==");
    	
    }
    }
    

兩者聯繫and區別:

  • 區別:

  • 常用接口方式來實現多線程:好處:

    1. 避免單繼承的侷限:‘
      子類可以實現多個接口,但是繼承只能繼承一個。比如student同時實現多線程,同時,又實現person的接口
    2. 共享同一個接口的對象==從而共同處理一份資源
      ex:
      • 兩個線程共同增加count 數值

      • 兩個線程共享同一個對象
        /new 同一個對象
        RunableTest r=new RunableTest();
        //參數r,被兩個線程共享
        Thread t2=new Thread(r, “t-2 :”);
        t2.start();
        //作用:多線程運行時,可以明確是具體哪個的線程在運行
        Thread t3=new Thread(r, “t-3 :”);
        t3.start();
        兩個線程同時對count進行++
        public class RunableTest implements Runnable {

         int count=0;
         @Override
         public void run() {
         	//System.out.println(Thread.currentThread().getName()+"  : 多線程運行代碼"+count);
         	for(int i=0;i<3;i++) {
         		//System.out.println(Thread.currentThread().getName()+"==="+i);
         		count++;
         		System.out.println(Thread.currentThread().getName()+"  : 多線程運行代碼"+count);
         	
             }
         
         }
        

        }

多線程優點

  1. 提高應用程序的響應
  2. CPU的利用率
  3. 改善程序結構:一個程序可以分成多個線程並行運行

thread類(2)的方法

  • join()阻塞:
    專業說法:阻塞當前的main方法,先不執行System.out.println("=====5=");
    先執行jion進來的代碼,jion的線程執行全部完畢之後繼續執行之前main阻塞的代碼
    RunableTest r=new RunableTest();
    Thread t2=new Thread(r, “t-2 :”);
    t2.start();
    Thread t3=new Thread(r, “t-3 :”);
    t3.start();

    	System.out.println("=======1==");
    	//把t2的run()方法添加到main中執行,
    	//執行順序一定是t2中的run一定在1與5之間
    	t2.join(); 
    	System.out.println("=======5===");
    	System.out.println("=======7==");
    
  • yield():線程讓步
    暫停現在執行的程序,

  • sleep():睡眠
    Thread.sleep(1000);
    在實現線程的run中調用; 單位是毫秒
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

  • stop():強制停止線程聲明週期
    RunableTest r=new RunableTest();
    Thread t2=new Thread(r, “t-2 :”);
    t2.start();
    Thread t3=new Thread(r, “t-3 :”);
    t3.start();

    	System.out.println("=======1==");
    	System.out.println(t2.isAlive());//確認還活着
    	
    	 t2.stop();//在這句話之前t-2可以執行,之後就不能執行
    	System.out.println("=======5===");
    	t3.join();
    	System.out.println("=======7==");
    

    t-2只執行了一次就消失了

  • boolean isAlive():判斷當前線程是否還存活

線程生命週期

  1. 新建:創建線程實例
  2. 就緒:執行了start()方法之後,進入隊列等待CPU的時間片
  3. 運行:run()方法開始執行
  4. 阻塞:run()被卡住
  5. 死亡:強制死亡stop();自然死亡;斷電;殺掉進程

線程死鎖

  • 成因:不同的線程佔用需要的同步資源不放手,相互等待對方釋放自己需要的同步資源
  • 解決方法:合理安排執行順序;如:加鎖順序一致

線程通信

  • wait():掛起線程==阻塞

  • notify():喚醒排隊中的最高級線程

  • notifyAll():喚醒所有線程
    //案例:實現:支付寶永遠先執行,如果微信想先執行,則阻塞他
    使用this:
    public synchronized void drawing8(int m) throws Exception {
    String name=Thread.currentThread().getName();

    		if(name.equals("微信")) {
    			this.wait(); //當前對象阻塞
    		}
    		//取錢數目超過餘額
    		if(money<m) {
    			System.out.println(name+"操作:賬戶金額不足,餘額爲:"+money);
    		}else {
    			System.out.println(name+"操作:賬戶原有金額:"+money);
    			money-=m;
    			System.out.println(name+"操作:賬戶提款金額:"+m);
    			System.out.println(name+"操作:賬戶提款之後金額:"+money);
    		}
    		if(name.equals("支付寶")) {
    			this.notify(); //喚醒當前最高優先級線程,處於就緒狀態
    		}
    	}
    

生產者消費者問題

P V原理的實現

package ThreadTest;
/**
 * 生產者消費者:
 *  
 * @author douer
 *
 */
/*
 * 1.生產者生產的時候不消費,消費時不是生產
 * 2. 產品數爲0開始生產,產品>5則停止生產
 * 3.產品數==5則開始消費,直到全部消費完成
 */
public class Test4 {
	public static void main(String[] args) {

		
		Clerk c=new Clerk();
		
		//生產者
		//創建一個線程
		//使用匿名類創建一個線程
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				//加鎖
				synchronized(c) {
					//無限循環:跳出條件在裏面
					while(true) {//考試時以爲這個沒用呢
						//產品數爲0開始生產;直到到達一定數額
						if(c.productNum==0) {
							System.out.println("=====開始生產:"+c.productNum);
							while(c.productNum<4) {
								System.out.println("目前庫存:"+c.productNum++);
							}
			                //生產完畢則跳出循環
							System.out.println("====生產完畢::::"+c.productNum);
							//生產完畢之後喚醒消費進程
							c.notify();
						}
						//產品還有,不生產,進程阻塞
						else {
							try {
								c.wait();
							} catch (Exception e) {
								
								e.printStackTrace();
							}
						}
						
						
					}
					
				}
				
			}
		}, "生產者").start();

	
	//消費者
        new Thread(new Runnable() {
		
		@Override
		public void run() {
			//加鎖
			synchronized(c) {
				//無限循環:跳出條件在裏面
				while(true) {
					//產品數爲0開始生產;直到到達一定數額
					if(c.productNum==4) {
						System.out.println("=====開始消費哦:"+c.productNum);
						while(c.productNum>0) {
							System.out.println("目前庫存:"+c.productNum--);
						}
		                //生產完畢則跳出循環
						System.out.println("====消費完畢::::"+c.productNum);
						c.notify();
					}
					//產品還有,不生產,進程阻塞
					else {
						try {
							c.wait();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					
				}
				
			}
			
		}
	}, "生產者").start();
	
	
	//
//	producer.start();
//	consum.start();
}
	
	
}
class Clerk{
	public  static int  productNum=0;
}
發佈了15 篇原創文章 · 獲贊 7 · 訪問量 4175
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章