Java Day11

多線程

目的

區(qū)分進程和線程的概念
進程:正在運行的一個程序QQ IDE 瀏覽器
系統(tǒng)會為這個進程分配獨立的內存資源
線程:具體執(zhí)行任務的最小單位
一個進程最少擁有一個線程(主線程 運行起來就執(zhí)行的線程)
線程之間是共享內存資源的(進程申請的)
線程之間可以通信(數據傳遞,多數為主線程和子線程)
每一個線程都有自己的運行回路(生命周期)
1個進程中可以開啟多條線程,每條線程可以并行(同時)執(zhí)行不同的任務
為什么需要創(chuàng)建子線程
如果在主線程中存在有比較耗時的操作:下載視頻 上傳文件 數據處理
這些操作會阻塞主線程 ,后面的任務必須等這些任務執(zhí)行完畢
之后才能執(zhí)行,用戶體驗比較差

為了不阻塞主線程 需要將耗時的任務放在子線程中去處理

技術

1.如何創(chuàng)建一個線程 Thread Runnable
2.線程的同步 synchronized ReentrantLock
3.主線程和子線程之間使用接口回調數據
3.線程之間的通信:synchronized (wait notify notifyAll)
ReentrantLock lock;
Condition c = lock.newCondition();
await signal signalAll

技術實現

  • 如何創(chuàng)建一個線程
    1.創(chuàng)建一個繼承Thread 實現run方法 方法里面就是具體需要執(zhí)行的代碼
class TestThread extends Thread{
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 100; i++) {
            System.out.println(name+":"+(i+1));
            if (this != MyClass.tt2) {
                if (i == 9) {
                    try {
                        MyClass.tt2.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        super.run();
    }
}

創(chuàng)建該類的對象來調用start方法
將tt2對象靜態(tài)化,實現共享
static TestThread tt2;

// main 方法里面執(zhí)行的代碼 是在主線程里面執(zhí)行的
         // 主線程的名稱為main
        String name = Thread.currentThread().getName();
        System.out.println(name);
        // 創(chuàng)建Thread的對象
    TestThread  tt = new TestThread();
        // 設置線程的名稱
        tt.setName("子線程1");
        // 開啟任務
   tt.start();
//        for (int i = 0; i < 5; i++) {
//          System.out.println("main:"+(i+1));
//        }
        tt2 = new TestThread();
        // 設置線程的名稱
        tt2.setName("子線程2");
        // 開啟任務
        tt2.start();

2.創(chuàng)建一個任務:創(chuàng)建一個類實現Runnable接口

class aThread extends Thread implements Runnable{
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
        }
    }
}
aThread at = new aThread();

        // 使用Thread操作這個任務
        Thread t = new Thread(at);
        t.setName("子線程1");
        t.start();

        Thread t2 = new Thread(at);
        t2.setName("子線程2");
        t2.start();

這個任務只做一次

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName()+":"+(i+1));
                }
            }
        });
        t.setName("子線程1");
        t.start();

創(chuàng)建線程的同時 直接開線程任務
// 不需要操作線程對象本身

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName()+":"+(i+1));
                }
            }
        }).start();

使用Lambda表達式
// 閱讀性差

        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+(i+1));
            }
        }).start();
  • 線程安全
    多個線程操作同一資源,線程無法確定自己什么時候被阻塞
    容易導致數據錯誤
    synchronized Lock 加鎖解鎖
    synchronized 同步監(jiān)聽器 需要一把鎖

    任何一個對象都有自己的一把鎖
    如果多個線程操作同一個代碼塊 并且需要同步
    那么就只能操作同一把鎖

    1.同步代碼塊
    synchronized (監(jiān)聽器/對象/鎖){

    }
    2.同步方法 同步監(jiān)聽器是當前對象本身
    必須確保多個對象調用的同步方法時操作的同一個對象
    public synchronized void test()
    本質上就是同步代碼塊

             等價于
                 synchronized(this){
                    test();
                 }
       
                 wait notify  notifyAll
       
                 Lock
                 ReentrantLock  可重入鎖
    

火車站賣票
// 全國的買票系統(tǒng)就一個
// 重慶 上海

 用于賣票的任務
class Ticket implements Runnable{
    // 定義所有車票的數量
   public static  int nums = 100;
    String name;
    public Ticket(String name){
        this.name = name;
    }

   static final Object obj = new Object();

    static ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            // 判斷有沒有票
            lock.lock();
  //          synchronized (obj) {
                if (nums > 0) {
                    System.out.println(name + "出票:" + i);
                    nums--;

                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                } else {
                    break;
                }
                lock.unlock();
            }
     //   }
    }
}
Ticket ticket1 = new Ticket("重慶");
        Thread t1 = new Thread(ticket1);
        t1.start();

        Ticket ticket2 = new Ticket("上海");
        Thread t2 = new Thread(ticket2);
        t2.start();

使用接口實現線程間數據回調
Person類
Agent類 線程里面

public class Agent extends Thread{
    AgentInterface target;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        System.out.println("開始找房子");
        System.out.println("---------");
        System.out.println("房子找到了 即將返回數據");

        target.callBack("房子在西南大學");
        super.run();
    }

    public interface AgentInterface{
        void callBack(String desc);
    }
}
public class Person implements Agent.AgentInterface {
    public void needHouse(){
        Agent xw = new Agent();
        xw.target = this ;
        xw.start();
    }

    @Override
    public void callBack(String desc) {
        System.out.println("我是小王,接收到你的數據了:"+desc);
    }
}

在main函數中創(chuàng)建對象調用函數
Person xw = new Person();
xw.needHouse();

運行結果
QQ圖片20190818210144.png

心得

主線程的使用注意:別將比較耗時的操作放到主線程中。

耗時操作會卡住主線程,嚴重影響UI的流暢度,給用戶一種“卡”的壞體驗

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Java-Review-Note——4.多線程 標簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,772評論 2 17
  • 本文出自 Eddy Wiki ,轉載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,298評論 0 14
  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 3,107評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態(tài)及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,597評論 1 15
  • 一、進程和線程 進程 進程就是一個執(zhí)行中的程序實例,每個進程都有自己獨立的一塊內存空間,一個進程中可以有多個線程。...
    阿敏其人閱讀 2,700評論 0 13

友情鏈接更多精彩內容