1. 程式人生 > >深入理解Java中的多執行緒

深入理解Java中的多執行緒

java中要想實現多執行緒,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。

對於直接繼承Thread的類來說,程式碼大致框架是:

class 類名 extends Thread{
方法1;
方法2;
…
public void run(){
// other code…
}
屬性1;
屬性2;
…
}

先看一個簡單的例子:

/**
 * @author Hashsound 繼承Thread類,直接呼叫run方法
 * */
class hello extends Thread {

	private String name;

	public hello() {
	}

	public hello(String name) {
		this.name = name;
	}

	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(name + "執行 " + i);
		}
	}

	public static void main(String[] args) {
		hello h1 = new hello("A");
		hello h2 = new hello("B");
		h1.run();
		h2.run();
	}
}
【執行結果】:
A執行     0
A執行     1
A執行     2
A執行     3
A執行     4
B執行     0
B執行     1
B執行     2
B執行     3
B執行     4

我們會發現這些都是順序執行的,說明我們的呼叫方法不對,應該呼叫的是start()方法。
當我們把上面的主函式修改為如下所示的時候:
public static void main(String[] args) {
        hello h1=new hello("A");
        hello h2=new hello("B");
        h1.start();
        h2.start();
}
然後執行程式,輸出的可能的結果如下:

B執行 0
B執行 1
B執行 2
A執行 0
A執行 1
A執行 2
B執行 3
B執行 4
A執行 3
A執行 4

因為需要用到CPU的資源,所以每次的執行結果基本是都不一樣的,呵呵。
注意:雖然我們在這裡呼叫的是start()方法,但是實際上呼叫的還是run()方法的主體。
那麼:為什麼我們不能直接呼叫run()方法呢?
我的理解是:執行緒的執行需要本地作業系統的支援。
如果你檢視start的原始碼的時候,會發現:
public synchronized void start() {

    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added 
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
     if (threadStatus != 0 || this != me)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
}
private native void start0();

注意我用紅色加粗的那一條語句,說明此處呼叫的是start0()。並且這個這個方法用了native關鍵字,次關鍵字表示呼叫本地作業系統的函式。因為多執行緒的實現需要本地作業系統的支援。
但是start方法重複呼叫的話,會出現java.lang.IllegalThreadStateException異常。
通過實現Runnable介面:
大致框架是:

來先看一個小例子吧:

class 類名 implements Runnable{
方法1;
方法2;
…
public void run(){
// other code…
}
屬性1;
屬性2;
…
}
/**
 * @author Hashsound 實現Runnable介面
 * */
class hello implements Runnable {
 
    public hello() {
 
    }
 
    public hello(String name) {
        this.name = name;
    }
 
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "執行     " + i);
        }
    }
 
    public static void main(String[] args) {
        hello h1=new hello("執行緒A");
        Thread demo= new Thread(h1);
        hello h2=new hello("執行緒B");
        Thread demo1=new Thread(h2);
        demo.start();
        demo1.start();
    }
    private String name;
}
【可能的執行結果】:

執行緒A執行     0
執行緒B執行    0
執行緒B執行    1
執行緒B執行    2
執行緒B執行    3
執行緒B執行    4
執行緒A執行     1
執行緒A執行     2
執行緒A執行     3
執行緒A執行     4

關於選擇繼承Thread還是實現Runnable介面?
其實Thread也是實現Runnable介面的:
class Thread implements Runnable {
    //…
public void run() {
        if (target != null) {
             target.run();
        }
     }
}

其實Thread中的run方法呼叫的是Runnable介面的run方法。不知道大家發現沒有,Thread和Runnable都實現了run方法,這種操作模式其實就是代理模式。

Thread和Runnable的區別:

如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享。
/**
 * @author Rollen-Holt 繼承Thread類,不能資源共享
 * */
class hello extends Thread {
    public void run() {
        for (int i = 0; i < 7; i++) {
            if (count > 0) {
                System.out.println("count= " + count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello h1 = new hello();
        hello h2 = new hello();
        hello h3 = new hello();
        h1.start();
        h2.start();
        h3.start();
    }
    private int count = 5;
}
【執行結果】:

count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1


大家可以想象,如果這個是一個買票系統的話,如果count表示的是車票的數量的話,說明並沒有實現資源的共享。

我們換為Runnable介面

class MyThread implements Runnable{
 
    private int ticket = 5;  //5張票
 
    public void run() {
        for (int i=0; i<=20; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName()+ "正在賣票"+this.ticket--);
            }
        }
    }
}
public class lzwCode {
     
    public static void main(String [] args) {
        MyThread my = new MyThread();
        new Thread(my, "1號視窗").start();
        new Thread(my, "2號視窗").start();
        new Thread(my, "3號視窗").start();
    }
}
【執行結果】:

count= 5
count= 4
count= 3
count= 2
count= 1

總結一下吧:

實現Runnable介面比繼承Thread類所具有的優勢:

1):適合多個相同的程式程式碼的執行緒去處理同一個資源

2):可以避免java中的單繼承的限制

3):增加程式的健壯性,程式碼可以被多個執行緒共享,程式碼和資料獨立。
所以,本人建議大家儘量實現介面。

/**
 * @author Hashsound
 * 取得執行緒的名稱
 * */
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        new Thread(he,"A").start();
        new Thread(he,"B").start();
        new Thread(he).start();
    }
}
【執行結果】:

A
A
A
B
B
B
Thread-0
Thread-0
Thread-0

說明如果我們沒有指定名字的話,系統自動提供名字。
提醒一下大家:main方法其實也是一個執行緒。在java中所以的執行緒都是同時啟動的,至於什麼時候,哪個先執行,完全看誰先得到CPU的資源。
在java中,每次程式執行至少啟動2個執行緒。一個是main執行緒,一個是垃圾收集執行緒。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個jVM實習在就是在作業系統中啟動了一個程序。

判斷執行緒是否啟動

/**
 * @author Hashsound 判斷執行緒是否啟動
 * */
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he);
        System.out.println("執行緒啟動之前---》" + demo.isAlive());
        demo.start();
        System.out.println("執行緒啟動之後---》" + demo.isAlive());
    }
}
【執行結果】

執行緒啟動之前---》false
執行緒啟動之後---》true
Thread-0
Thread-0
Thread-0
主執行緒也有可能在子執行緒結束之前結束。並且子執行緒不受影響,不會因為主執行緒的結束而結束。

執行緒的強制執行:

    /**
     * @author Hashsound 執行緒的強制執行
     * */
    class hello implements Runnable {
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName());
            }
        }
     
        public static void main(String[] args) {
            hello he = new hello();
            Thread demo = new Thread(he,"執行緒");
            demo.start();
            for(int i=0;i<50;++i){
                if(i>10){
                    try{
                        demo.join();  //強制執行demo
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("main 執行緒執行-->"+i);
            }
        }
    }
【執行的結果】:

main 執行緒執行-->0
main 執行緒執行-->1
main 執行緒執行-->2
main 執行緒執行-->3
main 執行緒執行-->4
main 執行緒執行-->5
main 執行緒執行-->6
main 執行緒執行-->7
main 執行緒執行-->8
main 執行緒執行-->9
main 執行緒執行-->10
執行緒
執行緒
執行緒
main 執行緒執行-->11
main 執行緒執行-->12
main 執行緒執行-->13
...
執行緒的休眠:
/**
 * @author Hashsound 執行緒的休眠
 * */
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he, "執行緒");
        demo.start();
    }
}
【執行結果】:(結果每隔2s輸出一個)

執行緒0
執行緒1
執行緒2


執行緒的中斷:
/**
 * @author Hashsound 執行緒的中斷
 * */
class hello implements Runnable {
    public void run() {
        System.out.println("執行run方法");
        try {
            Thread.sleep(10000);
            System.out.println("執行緒完成休眠");
        } catch (Exception e) {
            System.out.println("休眠被打斷");
            return;  //返回到程式的呼叫處
        }
        System.out.println("執行緒正常終止");
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he, "執行緒");
        demo.start();
        try{
            Thread.sleep(2000);
        }catch (Exception e) {
            e.printStackTrace();
        }
        demo.interrupt(); //2s後中斷執行緒
    }
}
【執行結果】:

執行run方法
休眠被打斷

在java程式中,只要前臺有一個執行緒在執行,整個java程式程序不會小時,所以此時可以設定一個後臺執行緒,這樣即使java程序小時了,此後臺執行緒依然能夠繼續執行。
/**
 * @author Hashsound 後臺執行緒
 * */
class hello implements Runnable {
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + "在執行");
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he, "執行緒");
        demo.setDaemon(true);
        demo.start();
    }
}

雖然有一個死迴圈,但是程式還是可以執行完的。因為在死迴圈中的執行緒操作已經設定為後臺運行了。

執行緒的優先順序:
/**
 * @author Hashsound 執行緒的優先順序
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+"執行"+i);
        }
    }
 
    public static void main(String[] args) {
        Thread h1=new Thread(new hello(),"A");
        Thread h2=new Thread(new hello(),"B");
        Thread h3=new Thread(new hello(),"C");
        h1.setPriority(8);
        h2.setPriority(2);
        h3.setPriority(6);
        h1.start();
        h2.start();
        h3.start();
    }
}
【執行結果】:

A執行0
A執行1
A執行2
A執行3
A執行4
B執行0
C執行0
C執行1
C執行2
C執行3
C執行4
B執行1
B執行2
B執行3
B執行4

但是請讀者不要誤以為優先順序越高就先執行。誰先執行還是取決於誰先去的CPU的資源、

另外,主執行緒的優先順序是5.

執行緒的禮讓。

線上程操作中,也可以使用yield()方法,將一個執行緒的操作暫時交給其他執行緒執行。
/**
 * @author Hashsound 執行緒的優先順序
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+"執行"+i);
            if(i==3){
                System.out.println("執行緒的禮讓");
                Thread.currentThread().yield();
            }
        }
    }
 
    public static void main(String[] args) {
        Thread h1=new Thread(new hello(),"A");
        Thread h2=new Thread(new hello(),"B");
        h1.start();
        h2.start();         
    }
}

A執行0
A執行1
A執行2
A執行3
執行緒的禮讓

A執行4
B執行0
B執行1
B執行2
B執行3

執行緒的禮讓

B執行4

同步和死鎖:

【問題引出】:比如說對於買票系統,有下面的程式碼:

/**
 * @author Hashsound 
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            if(count>0){
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}
【執行結果】:

5
4
3
2
1
0
-1

這裡出現了-1,顯然這個是錯的。,應該票數不能為負值。
如果想解決這種問題,就需要使用同步。所謂同步就是在統一時間段中只有有一個執行緒執行,
其他的執行緒必須等到這個執行緒結束之後才能繼續執行。
【使用執行緒同步解決問題】
採用同步的話,可以使用同步程式碼塊和同步方法兩種來完成。

【同步程式碼塊】:

語法格式:

synchronized(同步物件){
 //需要同步的程式碼
}
但是一般都把當前物件this作為同步物件。

比如對於上面的買票的問題,如下:
/**
 * @author Hashsound
 * */
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            synchronized (this) {
                if(count>0){
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(count--);
                }
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}
【執行結果】:(每一秒輸出一個結果)

5
4
3
2
1

【同步方法】

也可以採用同步方法。

語法格式為synchronized 方法返回型別方法名(引數列表){

    // 其他程式碼

}
現在,我們採用同步方法解決上面的問題。
/**
 * @author Hashsound
 * */
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 10; ++i) {
            sale();
        }
    }
 
    public synchronized void sale() {
        if (count > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(count--);
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread h1 = new Thread(he);
        Thread h2 = new Thread(he);
        Thread h3 = new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count = 5;
}
【執行結果】(每秒輸出一個)

5
4
3
2
1

提醒一下,當多個執行緒共享一個資源的時候需要進行同步,但是過多的同步可能導致死鎖。

此處列舉經典的生產者和消費者問題。

【生產者和消費者問題】

先看一段有問題的程式碼。
class Info {
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    private String name = "Rollen";
    private int age = 20;
}
 
/**
 * 生產者
 * */
class Producer implements Runnable{
    private Info info=null;
    Producer(Info info){
        this.info=info;
    }
     
    public void run(){
        boolean flag=false;
        for(int i=0;i<25;++i){
            if(flag){
                this.info.setName("Rollen");
                try{
                    Thread.sleep(100);
                }catch (Exception e) {
                    e.printStackTrace();
                }
                this.info.setAge(20);
                flag=false;
            }else{
                this.info.setName("chunGe");
                try{
                    Thread.sleep(100);
                }catch (Exception e) {
                    e.printStackTrace();
                }
                this.info.setAge(100);
                flag=true;
            }
        }
    }
}
/**
 * 消費者類
 * */
class Consumer implements Runnable{
    private Info info=null;
    public Consumer(Info info){
        this.info=info;
    }
     
    public void run(){
        for(int i=0;i<25;++i){
            try{
                Thread.sleep(100);
            }catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(this.info.getName()+"<---->"+this.info.getAge());
        }
    }
}
 
/**
 * 測試類
 * */
class hello{
    public static void main(String[] args) {
        Info info=new Info();
        Producer pro=new Producer(info);
        Consumer con=new Consumer(info);
        new Thread(pro).start();
        new Thread(con).start();
    }
}
【執行結果】:

Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20

大家可以從結果中看到,名字和年齡並沒有對於。

那麼如何解決呢?

1)加入同步

2)加入等待和喚醒

先來看看加入同步會是如何。
class Info {
     
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public synchronized void set(String name, int age){
        this.name=name;
        try{
            Thread.sleep(100);
        }catch (Exception e) {
            e.printStackTrace();
        }
        this.age=age;
    }
     
    public synchronized void get(){
        try{
            Thread.sleep(100);
        }catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(this.getName()+"<===>"+this.getAge());
    }
    private String name = "Rollen";
    private int age = 20;
}
 
/**
 * 生產者
 * */
class Producer implements Runnable {
    private Info info = null;
 
    Producer(Info info) {
        this.info = info;
    }
 
    public void run() {
        boolean flag = false;
        for (int i = 0; i < 25; ++i) {
            if (flag) {
                 
                this.info.set("Rollen", 20);
                flag = false;
            } else {
                this.info.set("ChunGe", 100);
                flag = true;
            }
        }
    }
}
 
/**
 * 消費者類
 * */
class Consumer implements Runnable {
    private Info info = null;
 
    public Consumer(Info info) {
        this.info = info;
    }
 
    public void run() {
        for (int i = 0; i < 25; ++i) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.info.get();
        }
    }
}
 
/**
 * 測試類
 * */
class hello {
    public static void main(String[] args) {
        Info info = new Info();
        Producer pro = new Producer(info);
        Consumer con = new Consumer(info);
        new Thread(pro).start();
        new Thread(con).start();
    }
}
【執行結果】:

Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100

從執行結果來看,錯亂的問題解決了,現在是Rollen 對應20,ChunGe對於100

,但是還是出現了重複讀取的問題,也肯定有重複覆蓋的問題。如果想解決這個問題,就需要使用Object類幫忙了、

,我們可以使用其中的等待和喚醒操作。

要完成上面的功能,我們只需要修改Info類飢渴,在其中加上標誌位,並且通過判斷標誌位完成等待和喚醒的操作,程式碼如下:
class Info {
     
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public synchronized void set(String name, int age){
        if(!flag){
            try{
                super.wait();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.name=name;
        try{
            Thread.sleep(100);
        }catch (Exception e) {
            e.printStackTrace();
        }
        this.age=age;
        flag=false;
        super.notify();
    }
     
    public synchronized void get(){
        if(flag){
            try{
                super.wait();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
         
        try{
            Thread.sleep(100);
        }catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(this.getName()+"<===>"+this.getAge());
        flag=true;
        super.notify();
    }
    private String name = "Rollen";
    private int age = 20;
    private boolean flag=false;
}
 
/**
 * 生產者
 * */
class Producer implements Runnable {
    private Info info = null;
 
    Producer(Info info) {
        this.info = info;
    }
 
    public void run() {
        boolean flag = false;
        for (int i = 0; i < 25; ++i) {
            if (flag) {
                 
                this.info.set("Rollen", 20);
                flag = false;
            } else {
                this.info.set("ChunGe", 100);
                flag = true;
            }
        }
    }
}
 
/**
 * 消費者類
 * */
class Consumer implements Runnable {
    private Info info = null;
 
    public Consumer(Info info) {
        this.info = info;
    }
 
    public void run() {
        for (int i = 0; i < 25; ++i) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.info.get();
        }
    }
}
 
/**
 * 測試類
 * */
class hello {
    public static void main(String[] args) {
        Info info = new Info();
        Producer pro = new Producer(info);
        Consumer con = new Consumer(info);
        new Thread(pro).start();
        new Thread(con).start();
    }
}
【程式執行結果】:
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
先在看結果就可以知道,之前的問題完全解決。

【程式執行結果】:
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
Rollen<===>20
先在看結果就可以知道,之前的問題完全解決。

相關推薦

深入理解Java停止執行

一.停止執行緒會帶來什麼? 對於單執行緒中,停止單執行緒就是直接使用關鍵字return或者break,但是在停止多執行緒時是讓執行緒在完成任務前去開啟另外一條執行緒,必須放棄當前任務,而這個過程是不可預測,所以必須去做好防備。 二.認識停止執行緒的幾個方法  2.1三個被棄用的方法 &n

java執行一定快嗎?看完就知道!!!

理解上下文切換   即使是單核處理器也支援多執行緒執行程式碼,CPU通過每個執行緒分配CPU時間片來實現這個機制.時間片是CPU分配給多個執行緒的時間,因為時間片非常短,所以CPU通過不停的切換執行緒執行,讓我們感覺多個執行緒是同時執行的,時間片一般是幾十毫秒(ms).  

Java執行併發體系知識點彙總

一、多執行緒 1、作業系統有兩個容易混淆的概念,程序和執行緒。 程序:一個計算機程式的執行例項,包含了需要執行的指令;有自己的獨立地址空間,包含程式內容和資料;不同程序的地址空間是互相隔離的;程序擁有各種資源和狀態資訊,包括開啟的檔案、子程序和訊號處理。 執行緒:表示程

java執行的建立和啟動(1)

多執行緒概述 1.什麼是多執行緒 執行緒是程式執行的一條路徑,一個程序中可以包含多條執行緒;多執行緒併發執行可以提高程式的效率 2.程序和執行緒之間的關係 作業系統可以同時執行多個任務,每個任務就是程序;程序可以同時執行多個任務,每個任務就是執

Java進階(四十二)Java執行使用匿名內部類的方式進行建立3種方式

Java中多執行緒使用匿名內部類的方式進行建立3種方式 package cn.edu.ujn.demo; // 匿名內部類的格式: public class ThreadDemo {

Java執行交替列印

一、兩執行緒交替列印數字和字母 要求控制檯中輸出的內容為 A1B2C3D4 這應該是多執行緒面試題中推簡單的筆試題了吧; 1.Object. notify()和Object.wait()實現; private void init (){ char

java 執行池 ExecutorService shutdonw及其執行執行完成判斷

1.線上程池 ExecutorService的使用過程中,主執行緒開啟了多個子執行緒,如果判斷所有子執行緒任務是否完成問題; 方法一: BusinessHandler b = new Busines

java 執行之死鎖淺析

出現死鎖的前提條件: 1.必須是至少2個以上的執行緒在執行; 2.同時要保證其中至少有兩個執行緒中的鎖(至少有兩個)是相同的,而且都有鎖的巢狀; 分析:首先要明確的是當兩個執行緒都擁有相同的鎖時候,誰先拿到鎖,誰就有執行權(比如執行緒①先拿到執行權),同時②執行緒就沒有執

java執行讀取同一個檔案的不同位置,執行讀取檔案

今天遇到一個問題,需要多個執行緒讀取同一個檔案的不同位置,提高效率,寫程式碼驗證了一下,把結果記錄下來。 首先我們寫個檔案,然後多執行緒讀取,以下是我實驗的程式碼: package com.alibaba.middleware.race; im

java執行筆記(一)

java對多執行緒程式設計提供了內建支援。多執行緒程式包含同時執行的兩個或多個部分。這種程式的每一部分被稱為一個執行緒,並且每一個執行緒定義了單獨的執行路徑。因此,多執行緒是特殊形式的多工處理。 程序:正在進行中的程式,是重量級任務,需要自己的地址空間。程序間通訊開銷很大,

深入理解併發程式設計 -- 執行(一)

併發程式設計 -- 多執行緒(一) 作者 : Stanley 羅昊 【轉載請註明出處和署名,謝謝!】 程序 在理解多執行緒之前,我們先需要了解什麼是程序? 程序說白了就是在你的記憶體空間中開闢出的一個獨立的空間; 如果還不理解的話,我再解釋一下; 想必各位之前都安裝過軟體吧,你安裝完軟體之後,在

深入理解併發程式設計 -- 執行(二)底層執行原理、執行狀態

併發程式設計 -- 多執行緒底層執行原理、執行緒狀態 作者 : Stanley 羅昊 多執行緒 -- 併發程式設計(一) : https://www.cnblogs.com/StanleyBlogs/p/10890906.html 【轉載請註明出處和署名,謝謝!】 多執行緒底層執行原理 說道底層執行

Java執行啟動,為什麼呼叫的是start方法,而不是run方法?

### 前言 大年初二,大家新年快樂,我又開始碼字了。寫這篇文章,源於在家和基友交流的時候,基友問到了,我猛然發現還真是這麼回事,多執行緒啟動呼叫的都是start,那麼為什麼沒人掉用run呢?於是開啟我的idea,翻一波程式碼,帶大家一探究竟。 ### 繼承thread類實現多執行緒 我們知道java有三種方

深入理解Java執行

在java中要想實現多執行緒,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。 對於直接繼承Thread的類來說,程式碼大致框架是: class 類名 extends Thread{ 方法1; 方法2; … public void run(){ /

執行——從生活理解什麼是執行

     每一個程式可以包含至少一個執行緒,而多個執行緒之間可以“併發”執行。        在介紹執行緒前先來用生活中最常見的一個小例子來理解什麼是執行緒:   &nbs

python執行event的使用-----------------即一個靈活的方法標誌位,類似於java的等待喚醒機制(python與java不同的地方)

event是python中一個特有的標誌位方法,他一共有三種方法 1.event.wait():如果標誌位設定了,它不做任何事,如果沒有設定,則將會鎖住,等待標誌位的設定 2.event.set():設定標誌位 3.event.clear():清除標誌位 這一種機制很

python執行開啟的兩種方式(內含有event的應用,即安全的機制,類似於java的等待喚醒機制,不會出現執行之間的錯亂問題)

 event是類似於java中的等待喚醒機制,具體方法參照上一篇CSDN 下面來介紹開啟執行緒的第一種方式 #Filename:threading1.py #開啟執行緒的第一種方式 import threading import time event=threadin

JAVA執行池的理解

為了更好的理解,首先來看一篇JAVA中的執行緒池介紹: 一、簡介 執行緒池類為 java.util.concurrent.ThreadPoolExecutor,常用構造方法為: ThreadPoolExecutor(int corePoolSize, int maxim

Android執行通訊:Handler的理解

Android中的Handler Android中Handler在我理解主要是為了解決執行緒間通訊。 使用Android的Handler機制主要要了解幾個類: Looper: 一個執行緒對應一個或者0個Looper,主執行緒在ActivityThread的時候會預設建立一個L

Java Runnable執行理解(簡單)

public class thread {     public static void main (String[] args) {         Th1 t1 = new Th1(1);         new Thread(t1).start(); //方法1         Th1 t2 = new