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

Java中多個(gè)線程交替循環(huán)執(zhí)行的實(shí)現(xiàn)

 更新時(shí)間:2024年01月25日 11:13:37   作者:坐看云起時(shí)_雨宣  
有些時(shí)候面試官經(jīng)常會(huì)問(wèn),兩個(gè)線程怎么交替執(zhí)行呀,本文就來(lái)詳細(xì)的介紹一下Java中多個(gè)線程交替循環(huán)執(zhí)行的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

有些時(shí)候面試官經(jīng)常會(huì)問(wèn),兩個(gè)線程怎么交替執(zhí)行呀,如果是三個(gè)線程,又怎么交替執(zhí)行呀,這種問(wèn)題一般人還真不一定能回答上來(lái)。多線程這塊如果理解的不好,學(xué)起來(lái)是很吃力的,更別說(shuō)面試了。下面我們就來(lái)剖析一下怎么實(shí)現(xiàn)多個(gè)線程順序輸出。

兩個(gè)線程循環(huán)交替打印

//首先我們來(lái)看一種比較簡(jiǎn)單的方式
public class ThreadCq {
	
	public static void main(String[] args) {
		 Stack<Integer> stack = new Stack<>();
		 for(int i=1;i<100;i++) {
			 stack.add(i);
		 }
		 Draw draw = new Draw(stack);
		 new Thread(draw).start();
		 new Thread(draw).start();
	}
}

class Draw implements Runnable{
	
	private Stack<Integer> stack;
	public Draw(Stack<Integer> stack) {
		this.stack = stack;
	}
	
	@Override
	public void run() {
		while(!stack.isEmpty()) {
			synchronized (this) {
				notify();
				System.out.println(Thread.currentThread().getName()+"---"+stack.pop());
				try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

這種方式是用Condition對(duì)象來(lái)完成的:

public class ThreadCq3 {

	//聲明一個(gè)鎖
	static ReentrantLock lock = new ReentrantLock();

	public static void main(String[] args) {
		
		//創(chuàng)建兩個(gè)Condition對(duì)象
		Condition c1 = lock.newCondition();
		Condition c2 = lock.newCondition();
		Stack<Integer> stack = new Stack<>();
		for (int i = 0; i <= 100; i++) {
			stack.add(i);
		}

		new Thread(() -> {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			while (true) {
				lock.lock();
				// 打印偶數(shù)
				try {
					if (stack.peek() % 2 != 0) {
						c1.await();
					}
					System.out.println(Thread.currentThread().getName() + "-----" + stack.pop());
					c2.signal();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}).start();

		
		new Thread(() -> {
			while (true) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				lock.lock();
				try {
					// 打印奇數(shù)
					if (stack.peek() % 2 != 1) {
						c2.await();
					}
					System.out.println(Thread.currentThread().getName() + "-----" + stack.pop());
					c1.signal();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}).start();
	}
}

這種方式是通過(guò)Semaphore來(lái)實(shí)現(xiàn)的:

public class ThreadCq4 {

	//利用信號(hào)量來(lái)限制
	private static Semaphore s1 = new Semaphore(1);
	private static Semaphore s2 = new Semaphore(1);

	public static void main(String[] args) {
		
		try {
			//首先調(diào)用s2為 acquire狀態(tài)
			s1.acquire();
//			s2.acquire();  調(diào)用s1或者s2先占有一個(gè)
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		
		new Thread(()->{
			while(true) {
				try {
					s1.acquire();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("A");
				s2.release();
			}
		}).start();
		
		new Thread(()->{
			while(true) {
				try {
					s2.acquire();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("B");
				s1.release();
			}
		}).start();
	}
}

上面就是三種比較常用的,最常用的要屬第一種和第二種。

三個(gè)線程交替打印輸出

上面我們看了兩個(gè)線程依次輸出的實(shí)例,這里我們來(lái)看看三個(gè)線程如何做呢。

public class LockCond {

	private static int count = 0;
	private static Lock lock = new ReentrantLock();
	
	
	public static void main(String[] args) {
		Condition c1 = lock.newCondition();
		Condition c2 = lock.newCondition();
		Condition c3 = lock.newCondition();
		
		new Thread(()->{
			while(true) {
				lock.lock();
				try {
					while(count %3 != 0) {
						//剛開(kāi)始count為0  0%3=0 所以此線程執(zhí)行  執(zhí)行完之后 喚醒現(xiàn)成2,由于此時(shí)count已經(jīng)進(jìn)行了++,所有while成立,c1進(jìn)入等待狀態(tài),其他兩個(gè)也一樣
						c1.await();
					}
					System.out.println(Thread.currentThread().getName()+"========:A");
					count++;
					//喚醒線程2
					c2.signal(); 
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}) .start();
		
		new Thread(()->{
			while(true) {
				lock.lock();
				try {
					while(count %3 != 1) {
						c2.await();
					}
					System.out.println(Thread.currentThread().getName()+"========:B");
					count++;
					//喚醒線程3
					c3.signal();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}) .start();
		
		new Thread(()->{
			while(true) {
				lock.lock();
				try {
					while(count %3 != 2) {
						c3.await();
					}
					System.out.println(Thread.currentThread().getName()+"========:C");
					count++;
					//喚醒線程1
					c1.signal();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}) .start();
	}
	
}

三個(gè)線程的也可以寫(xiě)三種,這里寫(xiě)一種就行了,寫(xiě)法和上面兩個(gè)線程的都一樣。大家可以自己試一下。

Condition介紹

我們?cè)跊](méi)有學(xué)習(xí)Lock之前,使用的最多的同步方式應(yīng)該是synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)同步方式了。配合Object的wait()、notify()系列方法可以實(shí)現(xiàn)等待/通知模式。Condition接口也提供了類似Object的監(jiān)視器方法,與Lock配合可以實(shí)現(xiàn)等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的。Object和Condition接口的一些對(duì)比。摘自《Java并發(fā)編程的藝術(shù)》

Condition接口常用方法

        condition可以通俗的理解為條件隊(duì)列。當(dāng)一個(gè)線程在調(diào)用了await方法以后,直到線程等待的某個(gè)條件為真的時(shí)候才會(huì)被喚醒。這種方式為線程提供了更加簡(jiǎn)單的等待/通知模式。Condition必須要配合鎖一起使用,因?yàn)閷?duì)共享狀態(tài)變量的訪問(wèn)發(fā)生在多線程環(huán)境下。一個(gè)Condition的實(shí)例必須與一個(gè)Lock綁定,因此Condition一般都是作為L(zhǎng)ock的內(nèi)部實(shí)現(xiàn)。

  • await() :造成當(dāng)前線程在接到信號(hào)或被中斷之前一直處于等待狀態(tài)。

  • await(long time, TimeUnit unit) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)。

  • awaitNanos(long nanosTimeout) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)。返回值表示剩余時(shí)間,如果在nanosTimesout之前喚醒,那么返回值 = nanosTimeout - 消耗時(shí)間,如果返回值 <= 0 ,則可以認(rèn)定它已經(jīng)超時(shí)了。

  • awaitUninterruptibly() :造成當(dāng)前線程在接到信號(hào)之前一直處于等待狀態(tài)。【注意:該方法對(duì)中斷不敏感】。

  • awaitUntil(Date deadline) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定最后期限之前一直處于等待狀態(tài)。如果沒(méi)有到指定時(shí)間就被通知,則返回true,否則表示到了指定時(shí)間,返回返回false。

  • signal() :?jiǎn)拘岩粋€(gè)等待線程。該線程從等待方法返回前必須獲得與Condition相關(guān)的鎖。

  • signal()All :?jiǎn)拘阉械却€程。能夠從等待方法返回的線程必須獲得與Condition相關(guān)的鎖。

Semaphore介紹

Semaphore 是 synchronized 的加強(qiáng)版,作用是控制線程的并發(fā)數(shù)量。就這一點(diǎn)而言,單純的synchronized 關(guān)鍵字是實(shí)現(xiàn)不了的。他可以保證某一個(gè)資源在一段區(qū)間內(nèi)有多少給線程可以去訪問(wèn)。

從源碼我們可以看出來(lái),它new了一個(gè)靜態(tài)內(nèi)部類,繼承Sync接口。他同時(shí)也提供了一些構(gòu)造方法

比如說(shuō)通過(guò)這個(gè)構(gòu)造方法可以創(chuàng)建一個(gè)是否公平的Semaphore類。關(guān)于公平鎖和非公平鎖大家可以看我的另外一篇文章。

到此這篇關(guān)于Java中多個(gè)線程交替循環(huán)執(zhí)行的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java線程交替循環(huán)執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中容器創(chuàng)建的四種方式示例

    Spring中容器創(chuàng)建的四種方式示例

    這篇文章主要介紹了Spring中容器創(chuàng)建的四種方式示例,Spring容器是Spring框架的核心部分,它負(fù)責(zé)管理和組織應(yīng)用程序中的對(duì)象,它提供了一種輕量級(jí)的、非侵入式的方式來(lái)實(shí)現(xiàn)對(duì)象的創(chuàng)建、依賴注入和生命周期管理,需要的朋友可以參考下
    2023-10-10
  • Spring-data-JPA使用時(shí)碰到的問(wèn)題以及解決方案

    Spring-data-JPA使用時(shí)碰到的問(wèn)題以及解決方案

    這篇文章主要介紹了Spring-data-JPA使用時(shí)碰到的問(wèn)題以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java實(shí)現(xiàn)對(duì)象轉(zhuǎn)CSV格式

    Java實(shí)現(xiàn)對(duì)象轉(zhuǎn)CSV格式

    CSV是一種逗號(hào)分隔值格式的文件,一般用來(lái)存儲(chǔ)數(shù)據(jù)的純文本格式文件。Java對(duì)象轉(zhuǎn)CSV,有現(xiàn)成的工具包,commons-lang3 的ReflectionToStringBuilder 就可以簡(jiǎn)單的解決的對(duì)象轉(zhuǎn)CSV,快跟隨小編一起學(xué)習(xí)一下吧
    2022-06-06
  • 淺談JSP是如何編譯成servlet并提供服務(wù)的

    淺談JSP是如何編譯成servlet并提供服務(wù)的

    JSP是Servlet的一種特殊形式,JSP頁(yè)面最終是編譯為Servlet執(zhí)行的,那么本文主要介紹了JSP是如何編譯成servlet并提供服務(wù)的,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java中怎樣使用JSON進(jìn)行文件解析

    Java中怎樣使用JSON進(jìn)行文件解析

    這篇文章主要介紹了Java中怎樣使用JSON進(jìn)行文件解析問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • SpringBoot深入探究四種靜態(tài)資源訪問(wèn)的方式

    SpringBoot深入探究四種靜態(tài)資源訪問(wèn)的方式

    這一節(jié)詳細(xì)的學(xué)習(xí)一下SpringBoot的靜態(tài)資源訪問(wèn)相關(guān)的知識(shí)點(diǎn)。像這樣的知識(shí)點(diǎn)還挺多,比如SpringBoot2的Junit單元測(cè)試等等。本章我們來(lái)了解靜態(tài)資源訪問(wèn)的四種方式
    2022-05-05
  • Java實(shí)現(xiàn)文件上傳的方法

    Java實(shí)現(xiàn)文件上傳的方法

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)文件上傳的方法,供大家參考,感興趣的朋友可以參考一下
    2016-05-05
  • 非常詳細(xì)的Java異常處理機(jī)制知識(shí)整理大全

    非常詳細(xì)的Java異常處理機(jī)制知識(shí)整理大全

    Java異常指在程序運(yùn)行時(shí)可能出現(xiàn)的一些錯(cuò)誤,比如試圖打開(kāi)一個(gè)根本不存在的文件等,異常處理將會(huì)改變程序的控制流程,讓程序有機(jī)會(huì)對(duì)錯(cuò)誤做出處理,下面這篇文章主要給大家介紹了關(guān)于Java異常處理機(jī)制知識(shí)整理的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • 淺談java中Math.random()與java.util.random()的區(qū)別

    淺談java中Math.random()與java.util.random()的區(qū)別

    下面小編就為大家?guī)?lái)一篇淺談java中Math.random()與java.util.random()的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • java時(shí)間格式的簡(jiǎn)單整理

    java時(shí)間格式的簡(jiǎn)單整理

    這篇文章主要介紹了java時(shí)間格式的簡(jiǎn)單整理,文中通過(guò)示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考一下
    2019-06-06

最新評(píng)論