1. 程式人生 > >Java 線程寶典

Java 線程寶典

種類 定義 rac 接口 demo art div ram 當前

此文 為垃圾文 本人復習用的 emmm

  • 多線程:指的是這個程序(一個進程)運行時產生了不止一個線程
  • 並行與並發:
    • 並行:多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。
    • 並發:通過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操作層面不是真正的同時。並發往往在場景中有公用的資源,那麽針對這個公用的資源往往產生瓶頸,我們會用TPS或者QPS來反應這個系統的處理能力。

  進程和線程的區分

  第一種實現方式:通過繼承Thread類來實現的 線程

    摘要:

  技術分享

code:

package com.java.Thread;

public class MyThread {
    
public static void main(String[] args){ Apple a1 = new Apple("壞蛋"); a1.start(); Apple a2 = new Apple("好人"); a2.start(); } } class Apple extends Thread{ private String name; public Apple(String name){ this.name = name; } public void
run(){ for (int i = 1; i < 10; i++){ System.out.println(name+""+i); } } }

每一個線程從的它的創建到銷毀都有一個狀態 如下是線程的各種狀態:

技術分享

線程的四種狀態

技術分享

然後實現現成的 第二種方式 實現 Runnable接口

  技術分享

code如下:

package cn.java.thread;

public class RunnableDemo {

    public static void main(String[] args) {
        Test t1 
= new Test("haoren"); Test t2 = new Test("hairen"); Thread th1 = new Thread(t1); Thread th2 = new Thread(t2); th1.start(); th2.start(); } } class Test implements Runnable{ private String name; public Test(String name){ this.name = name; } public void run(){ for(int i=0;i<10;i++){ System.out.println(name+":"+i); } } }

  Thread和Runnable的關系

1.Thread是Ruuable的之類

   2.實際上Thread和Runable的關系 跟代理設計模式很像, 這裏的Thread就是代理類。我們自己所實現的類才是real。

   Thread和Runnable的區別

    Runable可以共享數據

code如下:

package cn.java.thread;

public class ShareDemo {
    public static void main(String[] args) {
        Tickets t1 = new Tickets();
        
        Thread th1 = new Thread(t1);
        Thread th2 = new Thread(t1);
        th1.start();
        th2.start();
        
        
    }

}

class Tickets implements Runnable{
    private int ticket = 5;
    
    public void run(){
        for(int i=0;i<5;i++){
            if(ticket>0)
            System.out.print(ticket--);
            
        }
    }
}

然後 我說說這裏面的 一個叫做jojn()的東東 網上各種帖子眾說紛紜 而對他的理解就是 4個字 強制執行 做一個簡單的驗證吧.

package com.java.Thread;

public class MyJoin {
    public static void main(String[] ARGS){
        MyThread2 mt1 = new MyThread2();
        mt1.setName("線程1");
        mt1.start();
        for (int i = 0; i < 10; i++) {
            if(i==5){
                try {
                    mt1.join();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
            System.out.println(i);
        }


    }
}
class MyThread2 extends Thread {
    /*public MyThread(String string) {
    }*/

    public void run() {
        int i = 0;
        while (i < 10) {
            System.out.println(Thread.currentThread().getName());
            i++;
        }


    }
}

運行結果如下

技術分享

然後在 說說 interrupt 中斷 一個線程意味著在該線程完成任務之前停止其正在進行的一切,有效地中止其當前的操作。線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決於這個程序。雖然初次看來它可能顯得簡單,但是,你必須進行一些預警以實現期望的結果。你最好還是牢記以下的幾點告誡。

首先,忘掉Thread.stop方法。雖然它確實停止了一個正在運行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來的Java版本中,它將不復存在。

一些輕率的家夥可能被另一種方法Thread.interrupt所迷惑。盡管,其名稱似乎在暗示著什麽,然而,這種方法並不會中斷一個正在運行的線程(待會將進一步說明),正如Listing A中描述的那樣。它創建了一個線程,並且試圖使用Thread.interrupt方法停止該線程。Thread.sleep()方法的調用,為線程的初始化和中止提供了充裕的時間。線程本身並不參與任何有用的操作。

code如下:

package com.java.Thread;

public class MyInterrupt {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyThread3 mt = new MyThread3();
        mt.start();

        try {
            Thread.sleep(2000);
            System.out.println("main休眠結束");
        } catch (InterruptedException e) {

            e.printStackTrace();
        }

        mt.interrupt();

    }
}

class MyThread3 extends Thread{
    public void run(){
        System.out.println("進入run");
        try {
            Thread.sleep(8000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            //e.printStackTrace();
            System.out.println("run休眠結束!!!");//sleep被中斷會拋出InterruptedException 推薦直接拋出 不要捕獲
        }
        System.out.println("run運行結束");
    }

}

然後來到線程禮讓 俗話點說 就是 線程A是個君子 看見線程B是個 美女就幹什麽都讓著她 讓她先過..

code如下:

package com.java.Thread;
//線程禮讓
public class MyYield {
    public static void main(String[] ARGS){
        MyThred m1 = new MyThred();
            Thread t1 = new Thread(m1,"李四");
            Thread t2 = new Thread(m1,"王五");
            t1.start();
            t2.start();
    }
}
class MyThred implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName()+"運行>>>>>" + i);
            if (i==2) {
                System.out.println("線程禮讓");
                Thread.currentThread().yield();
            }
        }
    }
}

然後 來到 setdaenmo 後臺線程設置

Java中線程分為兩種類型:用戶線程守護線程。通過Thread.setDaemon(false)設置為用戶線程;通過Thread.setDaemon(true)設置為守護線程。如果不設置次屬性,默認為用戶線程。

用戶線程和守護線程的區別:

1. 主線程結束後用戶線程還會繼續運行,JVM存活;主線程結束後守護線程和JVM的狀態又下面第2條確定。

2.如果沒有用戶線程,都是守護線程,那麽JVM結束(隨之而來的是所有的一切煙消雲散,包括所有的守護線程)。

code如下:

package com.java.Thread;

public class SetDaemon {
    public static void main(String[] ARGS){
        Persons p1 = new Persons();
            Thread th = new Thread(p1);
                th.setDaemon(true);//如果不加此語句就永遠無法結束
        th.start();

    }
}
class Persons implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("哈哈哈哈哈哈sss");
        }
    }
}

然後 設置線程的優先級別 這點要說說 高的不一定會優先執行.

這是定義表

技術分享

通過 setPriority方法來執行

技術分享

來到重點中的重點 拿個小本本記住 線程安全

  導致線程安全出現的原因:

技術分享

技術分享

所以 我們為了解決這個問題 推出了 同步 synchronized

  技術分享

然後同步又有兩種模式 一種是同步代碼塊 另外一種是同步函數 這兩種同步加鎖的方式不一樣 = =且看我細細道來

  先看看code

package cn.tread;

public class TicketDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Person2 p1 = new Person2("haoren");
        Thread t1 = new Thread(p1);
        Thread t2 = new Thread(p1);
        t1.start();
        t2.start();

    }

}

class Person2 implements Runnable {
    private String name;
    private int tickets = 5;

    public Person2(String name) {
        this.name = name;
    }
   //同步代碼塊 需要的鎖是 任意對象~
    Object object1 = new Object();

    public void run() {

        for (int i = 0; i < 5; i++) {
            synchronized (object1) {//object1就是傳說中的鎖,要同步必須使用同一個鎖
                if (tickets > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {

                        e.printStackTrace();
                    }

                    System.out.println(tickets--);
                }
            }
        }

    }
}

觀察上面的代碼 我們 有了一個總結 同步代碼的鎖可以是任意對象

然後是同步的前提

技術分享

技術分享

同步的弊端

技術分享

然後我們說說同步函數

package cn.java.thread;

/*
 證明同步函數用的是this這把鎖
 */
public class Tickets1 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*
         * GetTickets gt1 = new GetTickets(); GetTickets gt2 = new GetTickets();
         * GetTickets gt3 = new GetTickets(); gt1.setName("窗口一");
         * gt2.setName("窗口二"); gt3.setName("窗口三"); gt1.start(); gt2.start();
         * gt3.start();
         */
        GetTickets2 gt = new GetTickets2();
        Thread th1 = new Thread(gt, "窗口一");
        Thread th2 = new Thread(gt, "窗口二");
        Thread th3 = new Thread(gt, "窗口三");
        th1.start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        gt.flag = true;
        th2.start();
        th3.start();
    }

}

class GetTickets2 implements Runnable {

    private int tickets = 10;
    boolean flag = false;
    Object ob = new Object();
    public void run() {
        if (flag) {
            for (int i = 0; i < 10; i++) {
                //synchronized (ob) {//如果用ob就無法同步
                synchronized (this) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "賣出" + (tickets--) + "號票"+":同步代碼塊");
                    }
                }
                
            }
            
        } else {
            for (int i = 0; i < 10; i++) {
                function();
                
            }

        }
    }

    public synchronized void function() {

        if (tickets > 0) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "賣出"
                    + (tickets--) + "號票"+":同步函數");
            
        }
    }

}
/*
 * class GetTickets extends Thread{ //private static int tickets = 10; private
 * int tickets = 10; public void run(){
 * 
 * for (int i = 0; i < 10; i++) { if(tickets>0){
 * System.out.println(Thread.currentThread().getName()+"賣出"+(tickets--)+"號票"); }
 * } } }
 */

通過 觀察我們不難發現

技術分享

余下的我在下一個分P寫...

Java 線程寶典