欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java多線程創(chuàng)建及線程安全詳解

 更新時間:2021年05月13日 09:30:01   作者:ITdfq  
多線程是日常開發(fā)中的常用知識,也是難用知識。通這篇文章主要給大家介紹了關于java多線程創(chuàng)建及線程安全的相關資料,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

什么是線程

  • 線程被稱為輕量級進程,是程序執(zhí)行的最小單位,它是指在程序執(zhí)行過程中,能夠執(zhí)行代碼的一個執(zhí)行單位。每個程序程序都至少有一個線程,也即是程序本身。

線程的狀態(tài)

  • 新建(New):創(chuàng)建后尚未啟動的線程處于這種狀態(tài)
  • 運行(Runable):Runable包括了操作系統線程狀態(tài)的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行,也有可能正在等待著CPU為它分配執(zhí)行時間。
  • 等待(Wating):處于這種狀態(tài)的線程不會被分配CPU執(zhí)行時間。等待狀態(tài)又分為無限期等待和有限期等待,處于無限期等待的線程需要被其他線程顯示地喚醒,沒有設置Timeout參數的Object.wait()、沒有設置Timeout參數的Thread.join()方法都會使線程進入無限期等待狀態(tài);有限期等待狀態(tài)無須等待被其他線程顯示地喚醒,在一定時間之后它們會由系統自動喚醒,Thread.sleep()、設置了Timeout參數的Object.wait()、設置了Timeout參數的Thread.join()方法都會使線程進入有限期等待狀態(tài)。
  • 阻塞(Blocked):線程被阻塞了,“阻塞狀態(tài)”與”等待狀態(tài)“的區(qū)別是:”阻塞狀態(tài)“在等待著獲取到一個排他鎖,這個時間將在另外一個線程放棄這個鎖的時候發(fā)生;而”等待狀態(tài)“則是在等待一段時間或者喚醒動作的發(fā)生。在程序等待進入同步區(qū)域的時候,線程將進入這種狀態(tài)。
  • 結束(Terminated):已終止線程的線程狀態(tài),線程已經結束執(zhí)行。

線程的生命周期 

多線程創(chuàng)建方法

繼承Thread

/**
 * @Author GocChin
 * @Date 2021/5/11 11:56
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(currentThread().getName()+"運行了");
    }
}
class Test{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        System.out.println(Thread.currentThread().getName()+":運行了");
        myThread.start();
    }
}

實現Runable接口創(chuàng)建多線程

/**
 * @Author GocChin
 * @Date 2021/5/11 12:37
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript: 實現Runable接口的方式創(chuàng)建多線程
 * 1.創(chuàng)建一個實現了Runable接口的類
 * 2.實現類去實現Runable中的抽象方法,run();
 * 3.創(chuàng)建實現類的對象
 * 4.將此對象作為參數傳遞到Thread類的構造器中,創(chuàng)建Thread類的對象
 * 5.通過Thread類的對象調用start()
 */
class MThread implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i<100;i++){
            if (i%2!=0){
                System.out.println(i);
            }
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
        //3.創(chuàng)建實現類的對象
        MThread mThread = new MThread();
        //4.將此對象作為參數傳遞到Thread類的構造器中,創(chuàng)建Thread類的對象
        Thread thread = new Thread(mThread);
        thread.start();
    }
}

Thread和Runable創(chuàng)建多線程對比

開發(fā)中:優(yōu)先使用Runable
1.實現的方式沒有類的單繼承的局限性。
2.實現的方式跟適合處理多個線程有共享數據的情況。
聯系:Thread類中也實現了Runable,兩種方式都需要重寫run()。

實現Callable接口

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author GocChin
 * @Date 2021/5/11 13:03
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class MCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for(int i=0;i<100;i++){
            sum+=i;
        }
        return sum;
    }
}
public class CallableTest {
    public static void main(String[] args) {
        //執(zhí)行Callable 方式,需要FutureTask 實現實現,用于接收運算結果
        FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new MCallable());
       
        new Thread(integerFutureTask).start();
        //接受線程運算后的結果
        Integer integer = null;
        try {
            integer = integerFutureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

與Runable相比,Callable功能更強大

相比run()方法可以有返回值
方法可以拋出異常
支持泛型的返回值
需要借助FutureTask類,比如獲取返回結果

使用線程池進行創(chuàng)建

線程池創(chuàng)建的好處

提高響應速度(減少了創(chuàng)建新線程的時間)

降低資源消耗(重復利用線程池中線程,不需要每次都創(chuàng)建)

便于線程管理:

  • corePoolSize:核心線程池的大小
  • maximumPoolSize:最大線程數
  • keepAliveTime:線程沒有任務時最多保持多長時間后悔中止
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author GocChin
 * @Date 2021/5/11 13:10
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class Thread1 implements Runnable{

    @Override
    public void run() {
        for (int i=1;i<30;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        //創(chuàng)建線程池
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        Thread1 threadPool = new Thread1();
        for (int i=0;i<5;i++){
            //為線程池分配任務
            executorService.submit(threadPool);
        }
        //關閉線程池
        executorService.shutdown();
    }
}

Thread中的常用方法

  • start():啟動當前線程;調用當前線程的run();
  • run():通常需要重寫Thread類中的此方法,將創(chuàng)建的線程要執(zhí)行的操作聲明在此方法中。
  • currentThread():靜態(tài)方法,返回當前代碼的線程。
  • getName():獲取當前線程的名字。
  • setName():設置當前線程的名字。
  • yield():釋放當前cpu的執(zhí)行權,切換線程執(zhí)行。
  • join():在線程a中調用線程b的join(),此時線程a會進入阻塞狀態(tài),知道線程b完全執(zhí)行完畢,線程a 才結束阻塞狀態(tài)。
  • stop():強制線程生命期結束。(過時了,不建議使用)
  • isAlive():判斷線程是否還活著。
  • sleep(long millitime):讓當前線程睡眠指定的事milltime毫秒。在指定的millitime毫秒時間內,當前線程是阻塞狀態(tài)。

線程的優(yōu)先級

線程的優(yōu)先級等級

  • MAX_PRIORITY:10
  • MIN_PRIORITY:1
  • NORM_PRIORITY:5

涉及的方法

  • getPriority():返回線程的優(yōu)先值
  • setPriority(int newPriority):改變線程的優(yōu)先級

說明

  • 線程創(chuàng)建時繼承父線程的優(yōu)先級
  • 低優(yōu)先級知識獲得調度的概率低,并非一定是在高優(yōu)先級線程之后才被調用

線程的同步

問題

多線程賣票

基于實現Runable的方式實現多線程買票

package demo2;

/**
 * @Author GocChin
 * @Date 2021/5/11 13:37
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript: 創(chuàng)建三個窗口買票,總票數為100張,使用Runable接口的方式
 *      存在線程安全問題,待解決
 */
class Thread2 implements Runnable{

    private  int ticket=100;
    @Override
    public void run() {
        while (true){
            if (ticket>0) {
                System.out.println(Thread.currentThread().getName() + ":買票,票號為:" + ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}
public class Test1 {
    public static void main(String[] args) {
        Thread2 thread2 = new Thread2();
        Thread t1 = new Thread(thread2);
        Thread t2 = new Thread(thread2);
        Thread t3 = new Thread(thread2);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t2.start();
        t3.start();
    }
}

實現結果,存在重復的票

實現結果

如果在買票方法中加入sleep函數

 public void run() {
        while (true){
            if (ticket>0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":買票,票號為:" + ticket);
                ticket--;
            }else {
                break;
            }
        }
    }

則運行結果可能會出現-1,表示也是不正常的

出現-1的結果

理想情況

賣票理想狀態(tài)

極端情況

極端情況

在java中,我們通過同步機制,來解決線程的安全問題。

同步代碼塊

synchronized(同步監(jiān)視器){
	//需要被同步的代碼
}

說明

  • 操作共享數據的代碼就是需要被同步的代碼。
  • 共享數據:多個線程共同操作的變量,比如本題中的ticket就是共享數據。
  • 同步監(jiān)視器:俗稱:鎖。任何一個類的對象都可以充當鎖。要求:多個線程必須要共用統一把鎖。
  • 同步的方式,解決了線程的安全問題—好處。但是操作同步代碼時,只能有一個線程參與,其他線程等待。相當于是一個單線程的過程,效率低。-----局限性
  • 使用Runable接口創(chuàng)建多線程的方式中,可以使用this關鍵字;在繼承Thread類中創(chuàng)建多線程中,慎用this充當同步監(jiān)視器,可以考慮使用當前類充當同步監(jiān)視器。Class clazz = Windows.class 因此 類也是一個對象
  • 包裹操作共享數據的代碼 不能多也不能少

修改之后的代碼:

package demo2;

/**
 * @Author GocChin
 * @Date 2021/5/11 13:37
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript: 創(chuàng)建三個窗口買票,總票數為100張,使用Runable接口的方式
 *      存在線程安全問題,待解決
 */
class Thread2 implements Runnable{

    private  int ticket=100;

    Object object = new Object();
    @Override
    public void run() {
        while (true){
            synchronized(object) { //括號中的內容可以直接使用當前對象this去充當
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":買票,票號為:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
public class Test1 {
    public static void main(String[] args) {
        Thread2 thread2 = new Thread2();
        Thread t1 = new Thread(thread2);
        Thread t2 = new Thread(thread2);
        Thread t3 = new Thread(thread2);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t2.start();
        t3.start();
    }
}

結果

運行結果

繼承Thread的方式,去使用同步代碼塊,需要將聲明的鎖對象設為statci,否則創(chuàng)建的對象的同步監(jiān)視器不唯一,就無法實現。

package demo2;

/**
 * @Author GocChin
 * @Date 2021/5/11 14:45
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class WindowsTest2 extends Thread{
    private static int ticket=100;
    private static   Object obj = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (obj){ //這里不能使用this去充當,可以直接寫一個Test.class   類也是對象
                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+":買票,票號為:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}
public class  Test2{
    public static void main(String[] args) {
        WindowsTest2 w1 = new WindowsTest2();
        WindowsTest2 w2 = new WindowsTest2();
        WindowsTest2 w3 = new WindowsTest2();
        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");
        w1.start();
        w2.start();
        w3.start();
    }
}

同步方法

如果操作共享數據的代碼完整的聲明在一個方法中,可以將此方法聲明為同步的。


通過實現Runable的方式實現同步方法。

package demo2;

/**
 * @Author GocChin
 * @Date 2021/5/11 13:37
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript: 創(chuàng)建三個窗口買票,總票數為100張,使用Runable接口的方式
 * 存在線程安全問題,待解決
 */
class Thread3 implements Runnable {

    private int ticket = 100;


    @Override
    public void run() {
        while (true) {
            show();
        }

    }
    private synchronized void show(){
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":買票,票號為:" + ticket);
            ticket--;
        }
    }
}

public class Test3 {
    public static void main(String[] args) {
        Thread3 thread3 = new Thread3();
        Thread t1 = new Thread(thread3);
        Thread t2 = new Thread(thread3);
        Thread t3 = new Thread(thread3);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t2.start();
        t3.start();
    }
}

通過實現繼承Thread的方式實現同步方法。使用的同步監(jiān)視器是this,則不唯一,就會報錯。所以將該方法定義為static。當前的同步換時期就變成Test4.class了

package demo2;

/**
 * @Author GocChin
 * @Date 2021/5/11 14:45
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class WindowsTest4 extends Thread{
    private static int ticket=100;
    private static   Object obj = new Object();

    @Override
    public void run() {
        while (true){
            show();
        }

    }
    public static synchronized void show(){//同步監(jiān)視器不是this了,而是當前的類
//    public synchronized void show(){//同步監(jiān)視器是this  ,t1,t2,t3
        if (ticket>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":買票,票號為:"+ticket);
            ticket--;
        }
    }
}
public class  Test4{
    public static void main(String[] args) {
        WindowsTest4 w1 = new WindowsTest4();
        WindowsTest4 w2 = new WindowsTest4();
        WindowsTest4 w3 = new WindowsTest4();
        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");
        w1.start();
        w2.start();
        w3.start();
    }
}

總結

  • 同步方法仍然設計到同步監(jiān)視器,只是不需要我們去顯示的聲明。
  • 非靜態(tài)的同步方法,同步監(jiān)視器是:this靜態(tài)的同步方法中,同步監(jiān)視器是類本身。

Lock鎖解決線程安全問題

synchronize與lock的異同

相同

  • 都可以解決線程安全問題

不同

  • synchronize機制在執(zhí)行相應的同步代碼以后,自動的釋放同步監(jiān)視器;Lock需要手動的啟動同步lock(),同時結束同步也需要手動的實現unlock()。

建議優(yōu)先使用順序

Lock------>同步代碼塊(已經進入了方法體,分配了相應資源)---->同步方法(在方法體之外)

package demo2;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author GocChin
 * @Date 2021/5/11 15:58
 * @Blog: itdfq.com
 * @QQ: 909256107
 * @Descript:
 */
class Lock1 implements Runnable{
    private int ticket=50;

    //1.實例化
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            try {
                //2.調用lock鎖定方法
                lock.lock();
                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售票,票號為:"+ticket);
                    ticket--;
                }else{
                    break;
                }
            } finally {
                //3.調用解鎖方法
                lock.unlock();
            }
        }
    }
}
public class LockTest1 {
    public static void main(String[] args) {
        Lock1 lock1 = new Lock1();
        Thread t1 = new Thread(lock1);
        Thread t2 = new Thread(lock1);
        Thread t3 = new Thread(lock1);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");
        t1.start();
        t2.start();
        t3.start();

    }
}

到此這篇關于java多線程創(chuàng)建及線程安全的文章就介紹到這了,更多相關java多線程創(chuàng)建內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java使用JMF實現音樂播放功能

    java使用JMF實現音樂播放功能

    這篇文章主要為大家詳細介紹了java使用JMF實現音樂播放的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Spring?Boot?整合?Reactor實例詳解

    Spring?Boot?整合?Reactor實例詳解

    這篇文章主要為大家介紹了Spring?Boot?整合?Reactor實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • Java日常練習題,每天進步一點點(41)

    Java日常練習題,每天進步一點點(41)

    下面小編就為大家?guī)硪黄狫ava基礎的幾道練習題(分享)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • MyBatis如何通過攔截修改SQL

    MyBatis如何通過攔截修改SQL

    這篇文章主要介紹了MyBatis如何通過攔截修改SQL問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • javaweb頁面附件、圖片下載及打開(實現方法)

    javaweb頁面附件、圖片下載及打開(實現方法)

    下面小編就為大家?guī)硪黄猨avaweb頁面附件、圖片下載及打開(實現方法)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • MyBatis通用Mapper實現原理及相關內容

    MyBatis通用Mapper實現原理及相關內容

    今天小編就為大家分享一篇關于MyBatis通用Mapper實現原理及相關內容,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • springboot使用Validator校驗方式

    springboot使用Validator校驗方式

    這篇文章主要介紹了springboot使用Validator校驗方式,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-01-01
  • Java數組的動態(tài)初始化和常見問題解析

    Java數組的動態(tài)初始化和常見問題解析

    本文介紹了數組動態(tài)初始化的概念,即在初始化時僅指定數組長度,系統會為數組分配初始值,而靜態(tài)初始化則手動指定數組元素,系統根據元素個數計算數組長度,這兩種初始化方式應用場景不同,另外,還講述了數組默認初始化值的規(guī)律及數組常見問題,如越界問題等
    2024-10-10
  • 簡單了解spring bean作用域屬性singleton和prototype的區(qū)別

    簡單了解spring bean作用域屬性singleton和prototype的區(qū)別

    這篇文章主要介紹了簡單了解spring bean作用域屬性singleton和prototype的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • SpringBoot2.0如何啟用https協議

    SpringBoot2.0如何啟用https協議

    這篇文章主要介紹了SpringBoot2.0如何啟用https協議,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06

最新評論