1. 程式人生 > >線程基礎知識(一)

線程基礎知識(一)

讀後感 應用 rup IE osi 很好 state lee IT

線程基礎知識(一)

看了Java多線程編程核心技術第一章,算是讀後感吧感覺自己基礎並不是很好。

並發和並行

並發:你在吃飯突然來了一個電話,然後你去接電話,接完電話再吃飯。

並行:你在吃飯突然來了一個電話,然後你邊吃飯邊接電話。

並發其實就是交替的進行,並行就是同時進行。

技術分享圖片

技術分享圖片

進程和線程和程序

參考https://blog.csdn.net/woaigaolaoshi/article/details/51039505

程序並不能單獨執行,只有將程序加載到內存中,系統為他分配資源後才能夠執行,這種執行的程序稱之為進程,也就是說進程是系統進行資源分配和調度的一個獨立單位,每個進程都有自己單獨的地址空間。所以說程序與進程的區別在於,程序是指令的集合,是進程運行的靜態描述文本,而進程則是程序在系統上順序執行時的動態活動。

但是進程存在著很多缺陷,主要集中在兩點:

(1).進程只能在同一時間幹一件事情,如果想同時幹兩件事或多件事情,進程就無能為力了。

(2).進程在執行的過程中如果由於某種原因阻塞了,例如等待輸入,整個進程就會掛起,其他與輸入無關的工作也必須等待輸入結束後才能順序執行。

為了解決上述兩點缺陷,引入了線程這個概念。

線程是進程的一個實體,也是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位,有時又被稱為輕權進程或輕量級進程,相對進程而言,線程是一個更加接近於執行體的概念,進程在執行過程中擁有獨立的內存單元,而線程自己基本上不擁有系統資源,也沒有自己的地址空間,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),線程的改變只代表了 CPU 執行過程的改變,而沒有發生進程所擁有的資源變化。除了CPU 之外,計算機內的軟硬件資源的分配與線程無關,但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。

舉個例子吧,QQ是騰訊的一個應用也是一個程序,當我們雙擊QQ輸入賬號和密碼點擊登錄時(將程序加載到內存中,系統為他分配資源)這就是一個進程。你可以打開任務管理器查看下。

技術分享圖片

要是你想找小明同學聊天,小紅同學聊天...打開的窗口就是線程。

Thread類和Runnable接口

繼承Thread類重寫run()方法

class MyThread extends Thread{
@Override
public void run(){
    System.out.println(Thread.currentThread().getName());
}

實現Runnable接口

class MyRunnable implements Runnable{

@Override
public void run() {
    System.out.println("myRunnable:"+Thread.currentThread().getName());
}
}

public class Test {
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
    Thread thread1=new Thread(new MyRunnable());
    thread1.start();
}
}

推薦使用Runnable,因為java是單繼承有局限性,而接口是多"繼承"(實現多個接口)。

幾個方法

currentThread()獲取當前線程

public class Test {
public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName());
}
}

技術分享圖片

isAlive()方法判斷當前線程是否活著

public class Test {
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
    System.out.println(thread.isAlive());
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(thread.isAlive());

}
}

class MyThread extends Thread{
@Override
public void run(){
    System.out.println(Thread.currentThread().getName());
}
} 

技術分享圖片


sleep()當前線程休眠讓出cpu使用,但是不讓出鎖 wait 會讓出鎖使用

public class Test {
    public static void main(String[] args) {
        MyRunnable runnable=new MyRunnable();
        Thread thread=new Thread(runnable);
        Thread thread1=new Thread(runnable);
        Thread thread2=new Thread(runnable);
        Thread thread3=new Thread(runnable);
        Thread thread4=new Thread(runnable);
        Thread thread5=new Thread(runnable);
        thread.start();
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        synchronized (Test.class) {
            System.out.println("myRunnable:" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}



public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        Thread thread4=new Thread(myThread);
        Thread thread5=new Thread(myThread);
        Thread thread6=new Thread(myThread);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();

    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}

技術分享圖片


wait(),notify(),notifyAll()是屬於Object類中。調用這3個方法時需要持有當前對象鎖資源不然會有java.lang.IllegalMonitorStateException 異常

生產者消費者。

public class PCModel {
    public static void main(String[] args) {
        //初始化storeHouse的大小
        int storeHouseSize=10;
        PriorityQueue<Integer> storeHouse=new PriorityQueue<>(storeHouseSize);
        Thread producer=new Thread(new Producer(storeHouse));
        Thread consumerOne=new Thread(new Consumer(storeHouse));
        Thread consumerTwo=new Thread(new Consumer(storeHouse));
        producer.start();
        consumerOne.start();
        consumerTwo.start();


    }



}

class Consumer implements Runnable{
    private Queue<Integer> storeHouse;
    public Consumer(Queue<Integer> storeHouse){
        this.storeHouse=storeHouse;
    }
    @Override
    public void run() {
        consume();
    }

    private void consume(){
        while(true){
            synchronized (storeHouse){
                while(storeHouse.size()==0){
                    try {
                        storeHouse.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //出隊列
                storeHouse.poll();
                System.out.println(Thread.currentThread().getName()+"消費了一個");
                storeHouse.notifyAll();
            }
        }
    }
}


class Producer implements Runnable{
    private Queue<Integer> storeHouse;
    public Producer(Queue<Integer> storeHouse){
        this.storeHouse=storeHouse;
    }
    @Override
    public void run() {
        produce();
    }

    private void produce(){
        while (true){
            synchronized (storeHouse){
                while (storeHouse.size()==10){
                    try {
                        storeHouse.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //生產
                storeHouse.add(1);
                System.out.println(Thread.currentThread().getName()+"添加了一個");
                storeHouse.notifyAll();
            }
        }
    }
}

getId()獲取線程的唯一標識

/**
 * Returns the identifier of this Thread.  The thread ID is a positive
 * <tt>long</tt> number generated when this thread was created.
 * The thread ID is unique and remains unchanged during its lifetime.
 * When a thread is terminated, this thread ID may be reused.
 *
 * @return this thread's ID.
 * @since 1.5
 */
public long getId() {
    return tid;
}

interrupted(),isInterrupted(),interrupt()

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        System.out.println(myThread.isInterrupted());
        myThread.interrupt();
        System.out.println(myThread.isInterrupted());

    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        for(int i=1;i<1000;i++){
            System.out.println(Thread.currentThread().getName()+"     "+i);
        }
    }
}

interrupt()不能停止線程,只是在打個停止的標記。isInterrupted()判斷線程是否已經中斷。

public class TestThread {
    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        System.out.println(Thread.interrupted());
        System.out.println(Thread.interrupted());
    }
}

interrupted()判斷當前線程是否中斷。interrupted()具有清除狀態功能。如上面結果第二次調用返回false。


線程在wait或sleep期間被中斷會拋出InterruptedException

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        myThread.interrupt();
    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        try {
            Thread.sleep(10000);
            //this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

一般當你調用sleep()方法或wait()方法後會自動提示你有異常要處理。


stop()方法為什麽被拋棄

public class TestThread {
    public static void main(String[] args) {
        Person person=new Person("aaaaaaaaaa","1");
        MyThread myThread=new MyThread(person);
        myThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.stop();
        System.out.println(person.getName()+"    "+person.getAge());

    }
}

class MyThread extends Thread{
    private Person person;

    public MyThread(Person person){
        this.person=person;
    }

    @Override
    public synchronized void run(){
        System.out.println(person.getName()+"    "+person.getAge());
        person.setName("abcd");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setAge("20");
        System.out.println(person.getName()+"    "+person.getAge());

    }
}

class Person{
    //姓名
    private String name;
    //年齡
    private String age;

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

stop()方法會造成數據不一致。


suspend()和resume()方法為什麽被拋棄

public class TestThread {
    public static void main(String[] args) {
        Person person = new Person("aaaa", 15);
        MyRunnable myRunnable = new MyRunnable(person);
        Thread thread = new Thread(myRunnable);
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setName("xiaoming");
        Thread thread1 = new Thread(new MyRunnable(person));
        thread1.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setName("AAAA");
        Thread thread2 = new Thread(new MyRunnable(person));
        thread2.start();


    }
}

class MyRunnable implements Runnable {
    private Person person;

    public MyRunnable(Person person) {
        this.person = person;
    }

    @Override
    public void run() {
        this.person.say();
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 say() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (name.equals("xiaoming"))
            Thread.currentThread().suspend();
        else
            System.out.println("name: " + this.name + " age:" + age);
    }
}

當把name改成xiaoming後第二個線程就一直占有資源,線程3進不去。

使用suspend與resume方法時使用不當會造成公共同步對象的獨占。


使用suspend與resume方法時會造成數據不同步。

yield方法的作用是放棄當前CPU資源,但放棄時間不確定

public class TestThread {
    public static void main(String[] args) {
       Thread thread=new Thread(new MyRunnable());
       thread.start();


    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        long start=System.currentTimeMillis();
        for (int i=0;i<1000000000;i++);
        Thread.yield();
        long end=System.currentTimeMillis();
        System.out.println(end-start);
    }
}

線程優先級高獲取的cpu資源比較多,線程中的優先級具有繼承性

public class TestThread {
    public static void main(String[] args) {
        FatherThread fatherThread = new FatherThread();
        SonThread sonThread = new SonThread();
        //優先級具有繼承性
        System.out.println("Father Priority:" + fatherThread.getPriority());
        System.out.println("Son Priority:" + sonThread.getPriority());


    }
}

class FatherThread extends Thread {
    @Override
    public void run() {
        System.out.println("Father");
    }
}

class SonThread extends FatherThread {

}

守護線程

以前太了解守護線程是幹啥的。現在知道守護線程就是為其他線程服務的等其它線程結束它才會結束。比如垃圾回收線程。

public class TestThread {
    public static void main(String[] args) {
        MyThread thread=new MyThread();
        thread.setDaemon(true);
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            try {
                System.out.println(i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

如何停止線程

使用interrupt()與return結合

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.interrupt();



    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()){
                System.out.println("Stop>>>>>>>>>>>>");
                return;
            }
            else
                System.out.println(System.currentTimeMillis());
        }
    }
}

總結

主要是Java多線程編程核心技術第一章的讀後感自己也動手敲了一遍對一些線程基礎理解更加深入了。加油加油!如果有一些問題歡迎指出來感謝。

線程基礎知識(一)