主頁 > 後端開發 > Java入門12(多執行緒)

Java入門12(多執行緒)

2023-07-13 07:44:47 後端開發

多執行緒

執行緒的實作方式

  1. 繼承 Thread 類:一旦繼承了 Thread 類,就不能再繼承其他類了,可拓展性差
  2. 實作 Runnable 介面:仍然可以繼承其他類,可拓展性較好
  3. 使用執行緒池

繼承Thread 類

? 不能通過執行緒物件呼叫 run() 方法,需要通過 t1.start() 方法,使執行緒進入到就緒狀態,只要進入到就緒狀態的執行緒才有機會被JVM調度選中

// 這是一個簡單的栗子
public class StudentThread extends Thread{
    public StudentThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        for (int i = 0; i < 2; i++) {
            System.out.println("This is a test thread!");
            System.out.println(this.getName());
        }
    }
}
// 啟動類
public static void main(String[] args) {
    Thread t1 = new StudentThread();
    // 不能通過執行緒物件呼叫run()方法
    // 通過 t1.start() 方法,使執行緒進入到就緒狀態,只要進入到就緒狀態的執行緒才有機會被JVM調度選中
    t1.start();
}

實作 Runable 介面

? 實作方式需要借助 Thread 類的建構式,才能完成執行緒物件的實體化

// 介還是一個簡單的栗子
public class StudentThreadRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 2; i++) {
            System.out.println("This is a test thread!");
            System.out.println(Thread.currentThread().getName());
        }
    }
}
// 啟動類
public static void main(String[] args) {
    // 實作方式需要借助 Thread 類的建構式,才能完成執行緒物件的實體化
    StudentThreadRunnable studentThreadRunnable = new StudentThreadRunnable();
    Thread t01 = new Thread(studentThreadRunnable);
    t01.setName("robot010");
    t01.start();
}

匿名內部類實作

? 在類中直接書寫一個當前類的子類,這個類默認不需要提供名稱,類名由JVM臨時分配

public static void main(String[] args) {
    Thread t01 = new Thread(){
        @Override
        public void run() {
            for (int i = 0; i < 2; i++) {
                System.out.println("This is a test thread!");
            }
            System.out.println(Thread.currentThread().getName()); // 執行緒名
            System.out.println(this.getClass().getName()); // 匿名執行緒類類名
        }
    };
    t01.start();
}

執行緒的休眠(sleep方法)

? sleep方法,會使當前執行緒暫停運行指定時間,單位為毫秒(ms),其他執行緒可以在sleep時間內,獲取JVM的調度資源

// 這是一個計時器
public class TimeCount implements Runnable{
    @Override
    public void run() {
        int count = 0;
        while(true){
            System.out.println(count);
            count++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
// 測驗類
public static void main(String[] args) {
    System.out.println("這是main方法運行的時候,開啟的主執行緒~~~");
    TimeCount timeCount = new TimeCount();
    Thread timeThread = new Thread(timeCount);
    System.out.println("開啟計時器");
    timeThread.start();

    System.out.println("主執行緒即將休眠>>>>>>>>>>>");
    try {
        Thread.sleep(20000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(">>>>>>>>>>>主執行緒休眠結束~~~~~");
}

執行緒的加入(join方法)

? 被 join 的執行緒會等待 join 的執行緒運行結束之后,才能繼續運行自己的代碼

public static void main(String[] args) {
    Thread thread01 = new Thread(){
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println("This is thread-01!");
            }
        }
    };
    thread01.start();
    try {
        thread01.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Thread thread02 = new Thread(){
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println("This is thread-02!");
            }
        }
    };
    thread02.start();
}
// thread02 會等待 thread01 完全跑完,才會開始自己的執行緒

執行緒的優先級(priority方法)

? 優先級高的執行緒會有更大的幾率競爭到JVM的調度資源,但是高優先級并不代表絕對,充滿玄學?

public static void main(String[] args) {
    Thread thread01 = new Thread(){
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println("This is thread-01! " + Thread.currentThread().getPriority());
            }
        }
    };
    Thread thread02 = new Thread(){
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println("This is thread-02! " + Thread.currentThread().getPriority());
            }
        }
    };
    thread01.setPriority(1);
    thread02.setPriority(10);
    // 盡管thread02優先級高于thread01,但是也有可能
    thread01.start();
    thread02.start();
}

執行緒的讓步(yield方法)

? 立刻讓出JVM的調度資源,并且重新參與到競爭中

public static void main(String[] args) {
    Thread thread01 = new Thread(){
        @Override
        public void run(){
            for (int i = 1; i <= 10; i++) {
                System.out.println("This is thread-01! " + i);
            }
        }
    };
    Thread thread02 = new Thread(){
        @Override
        public void run(){
            for (int i = 1; i <= 10; i++) {
                System.out.println("This is thread-02! " + i);
                Thread.yield();
            }
        }
    };
    thread01.start();
    thread02.start();
}

守護執行緒(Deamon)

? 會在其他非守護執行緒都運行結束之后,自身停止運行,(GC垃圾回識訓制就是一個典型的守護執行緒)

public static void main(String[] args) {
    Thread thread01 = new Thread(){
        @Override
        public void run(){
            int times = 0;
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("time pass " + ++times + "second");
            }
        }
    };
    Thread thread02 = new Thread(){
        @Override
        public void run(){
            for (int i = 1; i <= 10; i++) {
                System.out.println("This is thread-02! " + i);
            }
        }
    };
    // 將t1設定為守護執行緒
    thread01.setDaemon(true);
    thread01.start();
    thread02.start();
    // 延長主執行緒運行,便于觀察結果
    try {
        Thread.sleep(20000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println("main thread end \\(-_-)/");
}

執行緒同步

資料操作的原子性

? 具有原子性的操作,不會被其他執行緒打斷,類似(a++)的操作是不具備原子性的,因此很容易在多執行緒場景中出現誤差

synchronized 悲觀鎖(互斥性)

優缺點:保證了資料在多執行緒場景下的安全(保證執行緒安全),犧牲的是效率,鎖的獲取和釋放,其他執行緒被阻塞都會額外消耗性能

同步物件:被多個執行緒所競爭的資源物件叫做同步物件

核心作用: 確保執行緒在持有鎖的期間內,其他執行緒無法操作和修改指定資料(同步物件)

? 每一個同步物件都會持有一把執行緒鎖,當執行緒運行到synchronized 修飾的方法或代碼時,執行緒會自動獲取當前同步物件的執行緒鎖,在synchronized 修飾的方法或代碼塊運行結束后,該執行緒會自動釋放此執行緒鎖,在持有執行緒鎖的這段時間里,其他執行緒是無法執行synchronized 所修飾的代碼塊的,其他執行緒會被阻塞在synchronized 代碼塊之外,直到這把鎖被釋放,,,

// synchronized 的兩種寫法:
// 1. 寫在方法之前,修飾整個方法
public synchronized Ticket getTicket(){
    // 取票
    Ticket ticketTmp = null;
    if(!tickets.isEmpty()){
        ticketTmp = tickets.removeLast();
    }
    return ticketTmp;
}
// 2. 代碼塊,修飾代碼塊所包含的部分
public Ticket getTicket(){
    // 取票
    synchronized(this){
        Ticket ticketTmp = null;
        if(!tickets.isEmpty()){
            ticketTmp = tickets.removeLast();
        }
        return ticketTmp;
    }
}

執行緒死鎖

??一個執行緒可以持有多個不同的同步物件的鎖!!!當兩個執行緒同時想要持有相同一把鎖時,就會產生死鎖現象

wait notify notifyAll

? 這三個方法并不是通過執行緒呼叫,而是通過同步物件第哦啊用,所有物件都可以當作是同步物件,這三個方法是在Object類中定義的

方法 作用
wait 讓占用當前同步物件鎖的執行緒進行等待,并且釋放鎖,直到被喚醒時才會被恢復
notify 通知一個在當前同步物件上等待的執行緒 進行喚醒,讓其重新競爭鎖,并運行代碼
notifyAll 通知在當前同步物件上等待的所有執行緒,進行喚醒

生產者消費者模型

  1. 生產者執行緒負責提供用戶請求
  2. 消費者執行緒負責處理用戶請求
// 模擬生產者消費者
// 球(ball) => 資料
public class Ball {
    private int ballNum;
}
// 籃子(basket) => 資料容器
public class Basket {
    // 指標,指向最新放入的球
    private int index = 0;
    // 容器
    private Ball[] balls = new Ball[5];
    // 存操作
    public synchronized void ballPut(Ball ballTmp){
        // 不斷的判斷容器是否放滿,如果執行緒被喚醒,需要再此判斷,如果此時容器還是滿的,應該繼續等待
        while(index == balls.length){
            System.out.println("The basket is full~~");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 行程能推進到這里,說明容器并沒有滿,可以進行存操作
        balls[index++] = ballTmp;
        System.out.println("ballPut : " + index);
        // 此時可以喚醒等待的取操作執行緒
        this.notifyAll();
    }
    
    // 取操作
    public synchronized void ballGet(){
        // 不斷的判斷容器是否為空,如果執行緒被喚醒,需要再此判斷,如果此時容器還是空的,應該繼續等待
        while(index == 0){
            System.out.println("The basket is empty~~");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 行程能推進到這里,說明容器沒有被取空,可以進行取操作
        System.out.println("ballGet : " + (index - 1));
        balls[--index] = null;
        // 此時可以喚醒等待的存操作執行緒
        this.notifyAll();
    }
}
// 放球(ballPut) => 生產者
public class Producer implements Runnable{
    // 為了保證生產者和消費者系結的是同一個容器
    Basket basket;
    // 構造方法,方便傳參
    public Producer(Basket basket){
        this.basket = basket;
    }
    // 存操作
    @Override
    public void run() {
        // 模擬一共放10個球
        for (int i = 0; i < 20; i++) {
            Ball ballTmp = new Ball(i);
            basket.ballPut(ballTmp);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
// 拿球(ballOut) => 消費者
public class Consumer implements Runnable{
    // 為了保證生產者和消費者系結的是同一個容器
    Basket basket;
    // 構造方法,方便傳參
    public Consumer(Basket basket){
        this.basket = basket;
    }
    // 取操作
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            basket.ballGet();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
// 測驗啟動類
public static void main(String[] args) {
    // 實體化容器
    Basket basket = new Basket();
    // 實體化生產者,消費者
    Producer producer = new Producer(basket);
    Consumer consumer = new Consumer(basket);
    // 生產者執行緒
    new Thread(producer).start();
    // 等待,容器被裝滿
    try {
        Thread.sleep(8000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    // 消費者執行緒
    new Thread(consumer).start();
}

執行緒池和自定義執行緒池

優點:節約執行緒資源,讓執行緒池中的消費者執行緒不斷的去執行任務

  1. 需要準備一個存放業務的容器
  2. 只啟動固定數量的消費執行緒
  3. 生產者執行緒負責向任務容器中提交任務
  4. 程式開始時,任務容器為空,所有消費者執行緒都處于 wait 狀態
  5. 直到有一個生產者向任務容器中投入了一個任務,那么就會有一個消費者執行緒被 notify 喚醒,并執行此任務
  6. 任務執行完畢之后,該消費者執行緒會重新處于 wait 狀態,等待下一次任務到來
  7. ?(執行緒復用)整個任務流程,都不需要創建新的執行緒,而是對已經存在的執行緒回圈使用

模擬執行緒池基礎功能實作(沒有實作自動擴容)

public class ThreadPool {
    // 執行緒池的大小
    int threadPoolSize;
    // 任務容器中的任務 --> 執行緒
    LinkedList<Runnable> tasks = new LinkedList<>();
    // 提供一個 add 方法,用于向任務容器中添加任務
    public void add(Runnable r){
        synchronized (tasks){
            tasks.add(r);
            // 喚醒消費者執行緒,取走任務容器中的任務
            tasks.notifyAll();
        }
    }
    //建構式--初始化執行緒池
    public ThreadPool() {
        // 初始化執行緒池大小
        threadPoolSize = 10;
        // 定義10個消費者執行緒,并且將其實體化后start
        synchronized (tasks){
            for (int i = 0; i < threadPoolSize; i++) {
                new TaskConsumeThread("ThreadRobot-0" + i+1).start();
            }
        }
    }

    // 內部類--消費者執行緒
    class TaskConsumeThread extends Thread{
        // 重寫 Thread 類構造方法,方便給執行緒定義 name 屬性
        public TaskConsumeThread(String name) {
            super(name);
        }
        // 需要被執行的任務
        Runnable task;
        // 重寫 run 方法
        @Override
        public void run() {
            System.out.println(this.getName() + " running!");
            while (true){
                // 獲取任務容器 tasks 的鎖,避免多個消費者執行緒同時操作任務容器,保證任務容器的執行緒安全
                synchronized (tasks){
                    // 只要任務容器為空,需要 wait 方法,讓所有消費者執行緒等待
                    while (tasks.isEmpty()){
                        try {
                            tasks.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 脫離回圈能運行到這里,說明任務容器不為空!
                    // 當前消費者從任務容器中取出任務,并存再自己的 task 參考中
                    task = tasks.removeLast();
                    // 喚醒添加任務的執行緒
                    tasks.notifyAll();
                    System.out.println(this.getName() + " get task!");
                    // 啟動任務執行緒
                    new Thread(task).start();
                }
            }
        }
    }
}
// 啟動測驗類01
public static void main(String[] args) {
    ThreadPool threadPool = new ThreadPool();
    Scanner sc = new Scanner(System.in);
    String tmp;
    while (true) {
        tmp = sc.nextLine();
        Thread task = new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        threadPool.add(task);
    }
}

// 啟動測驗類02
public static void main(String[] args) {
    ThreadPool threadPool = new ThreadPool();
    int sleepTime = 1000;
    // 任務計數
    int[] count = {0};
    while (true) {
        Runnable runnableTmp = new Runnable() {
            @Override
            public void run() {
                // 通過訪問外部陣列地址,來實作控制
                System.out.println("執行任務" + (++count[0]));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        threadPool.add(runnableTmp);
        try {
            Thread.sleep(sleepTime);
            sleepTime = sleepTime > 100 ? sleepTime - 100 : sleepTime;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Java自帶的執行緒池使用

public static void main(String[] args) {
    // 引數含義:
    //  corePoolSize : 執行緒池中初始執行緒數量
    //  maximumPoolSize : 執行緒池中最大執行緒數量
    //  keepAliveTime : 臨時執行緒的最大存活時間
    //  TimeUnit.SECONDS : 存活時間的單位
    //  new LinkedBlockingDeque<Runnable>() : 存放任務的任務容器
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
    // 創建測驗任務執行緒
    Runnable runnableTmp = new Runnable() {
        @Override
        public void run() {
            System.out.println("This is a testRunnable!");
        }
    };
    // 將測驗任務拋入執行緒池即可
    threadPoolExecutor.execute(runnableTmp);
}

資料庫連接池

? 如果每有一個用戶使用連接,就新建一個連接的話,創建連接和關閉連接的程序是非常消耗性能的,且單一資料庫支持的連接總數是有上限的,如果短時間內并發量過大,資料庫的連接總數就會被消耗光,后續執行緒發起的資料庫連接就會失敗,那么連接池的作用就是:它會在使用之前,就創建好一定數量的連接,如果有執行緒需要使用連接,就從連接池中借用,而不是重新創建連接,使用完此連接之后,再將此連接歸還給連接池,整個程序中,連接池中的連接都不會被關閉,而是被重復使用,

模擬資料庫連接池實作

public class ConnectionPool {
    List<Connection> connections = new ArrayList<>();
    int size;
    // 準備建構式
    public ConnectionPool(int size) {
        this.size = size;
        init();
    }
    // 初始化連接池
    public void init(){
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for (int i = 0; i < size; i++) {
                Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/iweb?characterEncoding=utf8","root","123456");
                connections.add(c);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 獲取一個資料庫連接
    public synchronized Connection getConnection(){
        while (connections.isEmpty()){
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return connections.remove(0);
    }
    // 歸還一個資料庫連接
    public synchronized void returnConnection(Connection connectionTmp){
        connections.add(connectionTmp);
        this.notifyAll();
    }
}
// 測驗啟動類
public class Application {
    public static void main(String[] args) {
        ConnectionPool connectionPool = new ConnectionPool(3);
        // 創建100個執行緒用于測驗
        for (int i = 0; i < 100; i++) {
            new WorkingThread("Thread0" + i,connectionPool).start();
        }
    }

    static class WorkingThread extends Thread{
        private ConnectionPool connectionPool;

        public WorkingThread(String name,ConnectionPool cp){
            super(name);
            this.connectionPool = cp;
        }

        @Override
        public void run() {
            Connection connection = connectionPool.getConnection();
            System.out.println(this.getName() + " get the mysql connection!");
            try(Statement statement = connection.createStatement()){
                Thread.sleep(1000);
                statement.execute("select * from user");
            }catch (Exception e){
                e.printStackTrace();
            }
            connectionPool.returnConnection(connection);
        }
    }
}

druid 德魯伊資料庫連接池(明天再加)

Reentrantlock 悲觀鎖的另一種實作方式(明天再加)

volatile 樂觀鎖 Java記憶體模型(明天再加)

記憶體私有公有 指令重排序 可見性(明天再加)

一致性協議(明天再加)

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/557101.html

標籤:其他

上一篇:python學習筆記:繼承與超類

下一篇:返回列表

標籤雲
其他(162441) Python(38274) JavaScript(25531) Java(18294) C(15241) 區塊鏈(8275) C#(7972) AI(7469) 爪哇(7425) MySQL(7296) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5876) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4616) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2439) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) HtmlCss(1998) .NET技术(1987) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1883) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Java入門12(多執行緒)

    ## 多執行緒 ### 執行緒的實作方式 1. 繼承 Thread 類:一旦繼承了 Thread 類,就不能再繼承其他類了,可拓展性差 2. 實作 Runnable 介面:仍然可以繼承其他類,可拓展性較好 3. 使用執行緒池 #### 繼承Thread 類 ? 不能通過執行緒物件呼叫 run() 方法,需要 ......

    uj5u.com 2023-07-13 07:44:47 more
  • python學習筆記:繼承與超類

    與java類似,繼承的出現是為了提高代碼的重復利用率,避免多次輸入同樣的代碼。而超類就是java中的父類。 # 1.繼承 要指定超類,可在定義類時,在class陳述句中的類名后加上超類名 * 基類就是超類,派生類就是子類 格式 ``` class Dog: # pass class Bobo(Dog) ......

    uj5u.com 2023-07-13 07:43:17 more
  • SpringMVC

    # SpringMVC ## Spring集成web環境 ### 集成步驟 1. 匯入相關的坐標,spring的和web的 ```xml org.springframework spring-context 5.3.6 mysql mysql-connector-java 5.1.32 c3p0 c ......

    uj5u.com 2023-07-13 07:09:00 more
  • C語言:資料結構之單鏈表(三)

    上篇談了談尾插法和頭插法,這篇談談中間插入元素和洗掉。 1、中間插入元素 既然談到了要從中間插入那就得確定插入的位置是否合法了,我總不能鏈表總長為5,但是插入的位置是60,這就不對了。所以得先確定這個鏈表的長度為多少。這個比較簡單,就是在尋找尾部的程序中計數,直到走到最后一個節點。 代碼如下: in ......

    uj5u.com 2023-07-12 09:05:29 more
  • 一文了解 io.LimitedReader型別

    # 1. 引言 `io.LimitedReader` 提供了一個有限的讀取功能,能夠手動設定最多從資料源最多讀取的位元組數。本文我們將從 `io.LimitedReader` 的基本定義出發,講述其基本使用和實作原理,其次,再簡單講述下具體的使用場景,基于此來完成對`io.LimitedReader` ......

    uj5u.com 2023-07-12 09:05:18 more
  • 一文了解 io.LimitedReader型別

    # 1. 引言 `io.LimitedReader` 提供了一個有限的讀取功能,能夠手動設定最多從資料源最多讀取的位元組數。本文我們將從 `io.LimitedReader` 的基本定義出發,講述其基本使用和實作原理,其次,再簡單講述下具體的使用場景,基于此來完成對`io.LimitedReader` ......

    uj5u.com 2023-07-12 09:04:05 more
  • C語言:資料結構之單鏈表(三)

    上篇談了談尾插法和頭插法,這篇談談中間插入元素和洗掉。 1、中間插入元素 既然談到了要從中間插入那就得確定插入的位置是否合法了,我總不能鏈表總長為5,但是插入的位置是60,這就不對了。所以得先確定這個鏈表的長度為多少。這個比較簡單,就是在尋找尾部的程序中計數,直到走到最后一個節點。 代碼如下: in ......

    uj5u.com 2023-07-12 08:58:20 more
  • 【經典爬蟲案例】用Python爬取微博熱搜榜!

    [toc] # 一、爬取目標 您好,我是[@馬哥python說](https://www.zhihu.com/people/13273183132),一名10年程式猿。 本次爬取的目標是: [微博熱搜榜](https://s.weibo.com/top/summary?cate=realtimeho ......

    uj5u.com 2023-07-12 08:08:36 more
  • python學習筆記:第七章面向物件

    與java類似,python作為一種面向物件的編程語言,也可以創建自定義的物件和類。 它的特性主要有:繼承,封裝,多型,方法,屬性,超類 # 1.變數的作用域 ```python c = 50 #全域變數, 作用域為整個模塊,若被參考,可作用域整個包 def plus(x,y): c = x + y ......

    uj5u.com 2023-07-12 08:08:29 more
  • 【爬蟲案例】用Python爬取百度熱搜榜資料!

    [toc] # 一、爬取目標 您好,我是[@馬哥python說](https://www.zhihu.com/people/13273183132),一名10年程式猿。 本次爬取的目標是:[百度熱搜榜](https://top.baidu.com/board?tab=realtime) ![百度熱搜 ......

    uj5u.com 2023-07-12 08:08:16 more