java進程/線程;堆和棧;多線程

一.進程和線程java

進程:在內存中運行的應用程序,一個exe是一個進程。數據庫

如:ps -exf  能夠查看各個應用的進程,其中ppid爲父進程;數組

     ps aux | egrep '(cron|syslog)'      找出與 cron 與 syslog 這兩個服務有關的 PID 號碼  ;多線程

     kill -9 進程id 能夠關閉該進程jvm

線程:進程中的一個執行流程,共享同一個進程的內存。  ide

 

二.堆與棧函數

堆內存:存放new出來的對象和數組,分出的內存由jvm的自動垃圾回收器進行管理。this

棧內存:定義一個變量,取值等於new出來的對象和數組的首地址,即取一個變量名,實際的值存在堆內存中,地址放在定義的變量中,該變量被稱爲數組或對象的引用變量spa

堆保存實際數據,爲屬性內容,棧保存數值的空間地址,爲對象名稱).net

例如:int[] a=new int a[10]  爲堆內存分配一段連續的內存空間  

         a[2]=4   引用變量至關於給數組起個名字,之後能夠引用

內存分配:

1.類變量(static修飾):在堆中分配,堆中的內存地址存放在棧中,方便高速訪問

2.實例變量:如   a[2]=4  ,做爲堆對象的引用變量,引用完,被GC(garbage collection)垃圾回收器列入可回收的名單,可是不立刻釋放堆內存

3.局部變量:通常爲for循環內定義,執行時在棧中開闢內存,脫離做用域後,內存釋放,因此for內的變量通常定義在for內,而不是for外,防止佔用內存

具體內存分配參照:http://blog.csdn.net/qh_java/article/details/9084091

 

三.線程與內存

Thread類實例是一個對象,有變量和方法,生死於堆上

每一個線程實例有一個調用棧,每建立一個線程,就產生一個調用棧,記錄函數執行順序,開獨立棧是爲了並行運行

線程分類:1.用戶進程 (main爲主線程,其餘線程爲用戶進程)

              2.守護進程:程序運行時在後臺提供一種通用服務的線程,如:垃圾回收線程,內存管理線程,數據庫鏈接池監控線程

非守護線程結束,則守護線程沒有存在的必要,此時jvm退出,守護線程也關閉!!

 

四.線程的生命週期

線程生命週期的五種狀態:

(1)新建(new Thread)
建立Thread類的一個實例(對象)時,此線程進入新建狀態(未被啓動)。
例如:Thread  t1=new Thread();

(2)就緒(runnable)
線程已經被啓動,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候獲得CPU資源。例如:t1.start();

(3)運行(running)
線程得到CPU資源正在執行任務(run()方法),此時除非此線程自動放棄CPU資源或者有優先級更高的線程進入,線程將一直運行到結束。

當發生以下狀況是,線程會從運行狀態變爲阻塞狀態:

①、線程調用sleep方法主動放棄所佔用的系統資源

②、線程調用一個阻塞式IO方法,在該方法返回以前,該線程被阻塞

③、線程試圖得到一個同步監視器,但更改同步監視器正被其餘線程所持有

④、線程在等待某個通知(notify)

⑤、程序調用了線程的suspend方法將線程掛起。不過該方法容易致使死鎖,因此程序應該儘可能避免使用該方法。

(4)死亡(dead)
當線程執行完畢或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態等待執行。

天然終止:正常運行run()方法後終止

異常終止:調用stop()方法讓一個線程終止運行

(5)堵塞(blocked)
因爲某種緣由致使正在運行的線程讓出CPU並暫停本身的執行,即進入堵塞狀態。

正在睡眠:用sleep(long t) 方法可以使線程進入睡眠方式。一個睡眠着的線程在指定的時間過去可進入就緒狀態。

正在等待:調用wait()方法。(調用motify()方法回到就緒狀態)

被另外一個線程所阻塞:調用suspend()方法。(調用resume()方法恢復)

 

狀態控制和相關方法見:http://blog.csdn.net/lonelyroamer/article/details/7949969

 

五.如何建立多線程

多線程實現方式有2種:

(1)繼承Thread類(單繼承),並重寫run方法

(2)實現Runnable接口(當建立的類繼承了其餘類時)

ps:爲何要單繼承,多接口?--》防止繼承的多個類中有相同的方法,不易區分,而接口沒有方法體(多爲抽象方法),能夠多繼承

先來編寫一個單線程:

public class Mythread {
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
         Thread t =Thread.currentThread();
         t.setName("單例線程");
         System.out.println(t.getName()+" 正在運行");
         for(int i=0;i<5;i++){
             System.out.println("線程正在休眠:"+i);
             try {
                t.sleep(500);
            } catch (InterruptedException e) {
                System.out.println("線程出現錯誤了!!");
            }
         }
         
    }}

 

運行結果:

單例線程 正在運行
線程正在休眠:0
線程正在休眠:1
線程正在休眠:2
線程正在休眠:3
線程正在休眠:4

 

編寫一個多線程,使用第一種方法:

package thread;

public class Mythread3 extends Thread {

    private String name;
    private int ms;
    
//封裝線程名和時間
    
/*使用類方法,直接賦值類中的類方法,在該類被加載到內存時,就分配了相應的入口地址。
從而類方法不只能夠被類建立的任何對象調用執行,也能夠直接經過類名調用。類方法的入口地址直到程序退出才被取消。
類方法在類的字節碼加載到內存時就分配了入口地址,所以,Java語言容許經過類名直接調用類方法,而實例方法不能經過類名調用。*/
    public Mythread3(String name, int ms) {
         
        this.name = name;
        this.ms = ms;
    }
   
    
//  每一個線程start()後進行run()
    @Override
    public void run() {
        // TODO Auto-generated method stub
    try {
        sleep(ms);
        
    } catch (InterruptedException e) {
        // TODO: handle exception
        System.out.println("線程出錯啦");
        
    }
    System.out.println(name+"開始休眠"+ms);
        
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        Thread  t1=new Mythread3("線程1",100);
        Thread  t2=new Mythread3("線程2",300);
        Thread  t3=new Mythread3("線程3",200);
        t1.start();
        t2.start();
        t3.start();        
    }
}

 

運行結果:

線程1開始休眠100
線程3開始休眠200
線程2開始休眠300

 

使用第二種方法:

package thread;


    class MyThread extends Thread{
        public int x = 0;
        public void run(){
        System.out.println(++x);
        }
        }

    class R implements Runnable{
        private int x = 0;
        public void run(){
        System.out.println(++x);
        }
        }


    public class Test{
         public static void main(String[] args){
         
         try {
          for(int i=0;i<10;i++){
          Thread t = new MyThread();  //Mythread類繼承thread,使用方法(1),打印十次1
          t.start();
          }
          
          Thread.sleep(10000);//讓上面的線程運行完成
    
          /*R類使用接口runnable,使用方法(2),10個線程對象產生的10個線程運行時打印了1到10。
          10個線程稱爲同一實例(Runnable實例)的多個線程。*/
          R r = new R();
          for(int i=0;i<10;i++){
          Thread t1 = new Thread(r);
           t1.start();
              }
         } catch (Exception e) {
          // TODO: handle exception
         }
        }
        }

運行結果:

 

六.線程同步

臨界資源:多個線程共享的數據

java對象默承認以被多個線程共用,當用sychronized修飾時,則啓動「互斥鎖」機制,任一時刻只能由一個線程訪問,即便該線程阻塞。

線程同步的方法有兩種:

(1)synchronized(互斥鎖)

(2)wait與notify

可見: http://blog.csdn.net/ff55c/article/details/6748604

相關文章
相關標籤/搜索