成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

springboot中怎么利用service實現(xiàn)多線程

今天就跟大家聊聊有關(guān)springboot中怎么利用service實現(xiàn)多線程,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計、網(wǎng)站制作、外貿(mào)營銷網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)襄陽免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了成百上千企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

線程安全:既然是線程安全問題,那么毫無疑問,所有的隱患都是在多個線程訪問的情況下產(chǎn)生的,也就是我們要確保在多條線程訪問的時候,我們的程序還能按照我們預(yù)期的行為去執(zhí)行,我們看一下下面的代碼:

   Integer count = 0;
   public void getCount() {
       count ++;
       System.out.println(count);
   }

我開啟的3條線程,每個線程循環(huán)10次,得到以下結(jié)果:

springboot中怎么利用service實現(xiàn)多線程

我們可以看到,這里出現(xiàn)了兩個26,出現(xiàn)這種情況顯然表明這個方法根本就不是線程安全的,出現(xiàn)這種問題的原因有很多。

最常見的一種,就是我們A線程在進(jìn)入方法后,拿到了count的值,剛把這個值讀取出來,還沒有改變count的值的時候,結(jié)果線程B也進(jìn)來的,那么導(dǎo)致線程A和線程B拿到的count值是一樣的。

那么由此我們可以了解到,這確實不是一個線程安全的類,因為他們都需要操作這個共享的變量。其實要對線程安全問題給出一個明確的定義,還是蠻復(fù)雜的,我們根據(jù)我們這個程序來總結(jié)下什么是線程安全。

當(dāng)多個線程訪問某個方法時,不管你通過怎樣的調(diào)用方式、或者說這些線程如何交替地執(zhí)行,我們在主程序中不需要去做任何的同步,這個類的結(jié)果行為都是我們設(shè)想的正確行為,那么我們就可以說這個類是線程安全的。 

搞清楚了什么是線程安全,接下來我們看看Java中確保線程安全最常用的兩種方式。先來看段代碼。

springboot中怎么利用service實現(xiàn)多線程

大家覺得這段代碼是線程安全的嗎?
    毫無疑問,它絕對是線程安全的,我們來分析一下,為什么它是線程安全的?
    我們可以看到這段代碼是沒有任何狀態(tài)的,就是說我們這段代碼,不包含任何的作用域,也沒有去引用其他類中的域進(jìn)行引用,它所執(zhí)行的作用范圍與執(zhí)行結(jié)果只存在它這條線程的局部變量中,并且只能由正在執(zhí)行的線程進(jìn)行訪問。當(dāng)前線程的訪問,不會對另一個訪問同一個方法的線程造成任何的影響。
兩個線程同時訪問這個方法,因為沒有共享的數(shù)據(jù),所以他們之間的行為,并不會影響其他線程的操作和結(jié)果,所以說無狀態(tài)的對象,也是線程安全的。

添加一個狀態(tài)呢?

如果我們給這段代碼添加一個狀態(tài),添加一個count,來記錄這個方法并命中的次數(shù),每請求一次count+1,那么這個時候這個線程還是安全的嗎?

public class ThreadDemo {
   int count = 0; // 記錄方法的命中次數(shù)
   public void threadMethod(int j) {

       count++ ;

       int i = 1;

       j = j + i;
   }
}

很明顯已經(jīng)不是了,單線程運行起來確實是沒有任何問題的,但是當(dāng)出現(xiàn)多條線程并發(fā)訪問這個方法的時候,問題就出現(xiàn)了,我們先來分析下count+1這個操作。

進(jìn)入這個方法之后首先要讀取count的值,然后修改count的值,最后才把這把值賦值給count,總共包含了三步過程:“讀取”一>“修改”一>“賦值”,既然這個過程是分步的,那么我們先來看下面這張圖,看看你能不能看出問題:

springboot中怎么利用service實現(xiàn)多線程

可以發(fā)現(xiàn),count的值并不是正確的結(jié)果,當(dāng)線程A讀取到count的值,但是還沒有進(jìn)行修改的時候,線程B已經(jīng)進(jìn)來了,然后線程B讀取到的還是count為1的值,正因為如此所以我們的count值已經(jīng)出現(xiàn)了偏差,那么這樣的程序放在我們的代碼中,是存在很多的隱患的。

springboot中,多線程實現(xiàn)service

首先看一下Dao的實現(xiàn):

@Repository
@Slf4j
public class UserThreadDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String username, int threadId, String thread_status) {
        String sql = "insert into userthread (username, thread_id, thread_status) values (?,?,?)";
        jdbcTemplate.update(sql, new Object[]{username, threadId, thread_status});
        log.info("threadId:{}, jdbcTemplate:{}", threadId, jdbcTemplate);
    }

    public void update(String username, int threadId, String thread_status) {
        String sql = "update userthread set thread_status=? where username=? and thread_id=?";
        jdbcTemplate.update(sql, new Object[]{thread_status, username, threadId});
    }

}

這里的JDBCTemplate是一個線程安全的類,原因是JdbcTemplate使用了ThreadLocal實現(xiàn),使各線程能夠保持各自獨立的一個對象,其實就是一個變量副本,實現(xiàn)了線程安全。

因此在這個UserThreadDao中沒有共享數(shù)據(jù),沒有成員變量(JdbcTemplate是線程安全的),因此是線程安全的。

在service中使用多線程來調(diào)用dao,代碼如下所示:

@Service
@Slf4j
public class UserThreadServiceImpl implements UserThreadService {

    @Autowired
    UserThreadDao userThreadDao;

    @Override
    @Async("asyncServiceExecutor")
    public void serviceTest(String username) {
        log.info("開啟執(zhí)行一個Service, 這個Service執(zhí)行時間為30s, threadId:{}",Thread.currentThread().getId());
        userThreadDao.add(username, Integer.parseInt(Thread.currentThread().getId() +""), "started");
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("執(zhí)行完成一個Service, threadId:{}",Thread.currentThread().getId());
        userThreadDao.update(username, Integer.parseInt(Thread.currentThread().getId() +""), "ended");
    }
}

這里的serviceTest方法就是一個多線程方法。線程池的配置如下:

@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
    @Autowired
    VisiableThreadPoolTaskExecutor visiableThreadPoolTaskExecutor;

    @Bean
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = visiableThreadPoolTaskExecutor;
        //配置核心線程數(shù)
        executor.setCorePoolSize(5);
        //配置最大線程數(shù)
        executor.setMaxPoolSize(5);
        //配置隊列大小
        executor.setQueueCapacity(5);
        //配置線程池中的線程的名稱前綴
        executor.setThreadNamePrefix("async-service-");

        // rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時候,如何處理新任務(wù)
        // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來執(zhí)行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //執(zhí)行初始化
        executor.initialize();

        return executor;
    }
}

看完上述內(nèi)容,你們對springboot中怎么利用service實現(xiàn)多線程有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

分享名稱:springboot中怎么利用service實現(xiàn)多線程
網(wǎng)址分享:http://jinyejixie.com/article2/jjiioc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、電子商務(wù)關(guān)鍵詞優(yōu)化、網(wǎng)站導(dǎo)航、做網(wǎng)站、移動網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)
措勤县| 湘潭县| 佳木斯市| 罗江县| 阿鲁科尔沁旗| 苗栗县| 双牌县| 桃源县| 进贤县| 台州市| 龙南县| 板桥市| 陵水| 凌海市| 分宜县| 寿光市| 德清县| 泊头市| 韶山市| 涪陵区| 凌海市| 教育| 固阳县| 教育| 双鸭山市| 景泰县| 安新县| 宁德市| 岫岩| 马山县| 旅游| 大丰市| 宜春市| 拉孜县| 安塞县| 宁都县| 牡丹江市| 汾阳市| 沙田区| 崇信县| 玛纳斯县|