Teknologian jakaminen

[Käyttöjärjestelmä] Estojono ja tuottaja-kuluttaja-malli

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

estävä jono

1. Konsepti

Estojono on erityinen jono. Se noudattaa myös "first in, first out" -periaatetta.

Estojono voi olla säikeille turvallinen tietorakenne, ja sillä on seuraavat ominaisuudet:

  • Kun jono on täynnä, jonoon siirtymisen jatkaminen estää, kunnes muut säikeet ottavat elementtejä jonosta..
  • Kun jono on tyhjä, myös jonosta poistamisen jatkaminen estetään, kunnes muut säikeet lisäävät elementtejä jonoon.

Tyypillinen estojonon sovellusskenaario on "tuottaja-kuluttaja-malli". Tämä on hyvin tyypillinen kehitysmalli
tuottaja

Kuluttajamalli ratkaisee tuottajien ja kuluttajien välisen vahvan kytkentäongelman kontin kautta.

Tuottajat ja kuluttajat eivät ole yhteydessä toisiinsa, vaan kommunikoivat estojonojen kautta. Siksi tuottajan ei tarvitse odottaa, että kuluttaja käsittelee sen, vaan se heittää sen suoraan estojonoon ei kysy tuottajalta tietoja, vaan se otetaan suoraan estojonosta.

Tuottaja-kuluttaja-mallin toteuttamisessa on kaksi päävaihetta:

  1. toteuttaa tuottaja
  2. ymmärtää kuluttaja

2. Estojono vakiokirjastossa

Java-standardikirjastoon on sisäänrakennettu estojono. Jos meidän on käytettävä estojonoja joissakin ohjelmissa, voimme käyttää estojonoa suoraan vakiokirjastossa.
Voi.

  • BlockingQueue on käyttöliittymä. Todellinen toteutusluokka on LinkedBlockingQueue
  • Put-menetelmää käytetään estämään jonoon pääsy ja take-menetelmää jonosta poistumisen estoon.
  • BlockingQueuessa on myös menetelmiä, kuten tarjous, kysely ja kurkistus, mutta näillä menetelmillä ei ole estoominaisuuksia.

Estojonon pseudokoodi on seuraava:

BlockingQueue<String> queue = new LinkedBlockingQueue<>();

// ⼊队列
queue.put("abc");

// 出队列. 如果没有 put 直接 take, 就会阻塞.
String elem = queue.take();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3. Tuottaja-kuluttaja -malli

public static void main(String[] args) throws InterruptedException {

	BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();
	
	Thread customer = new Thread(() -> {
		while (true) {
			try {
				int value = blockingQueue.take();
				System.out.println("消费元素: " + value);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}, "消费者");
	
customer.start();

	Thread producer = new Thread(() -> {
		Random random = new Random();
		while (true) {
			try {
				int num = random.nextInt(1000);
				System.out.println("生产元素: " + num);
				blockingQueue.put(num);
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}, "生产者");
	
	producer.start();
	customer.join();
	producer.join();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

4. Estojonon toteutus

  1. Tämä saavutetaan "pyöreäjono"-menetelmällä.
  2. Käytä synkronoitua lukituksen ohjaukseen.
  3. Kun put lisää elementin, se määrittää, onko jono täynnä, ja odottaa (Huomaa, että odotus on suoritettava silmukassa. Kun se herätetään, jono ei välttämättä ole täynnä, koska useita säiettä voidaan herättää samanaikaisesti.) .
  4. Kun take ottaa pois elementin, se määrittää, onko jono tyhjä, ja odottaa (Se on myös silmukan odotus).
public class BlockingQueue {

	private int[] items = new int[1000];
	private volatile int size = 0;
	private volatile int head = 0;
	private volatile int tail = 0;
	
	public void put(int value) throws InterruptedException {
		synchronized (this) {
		// 此处最好使⽤ while.
		// 否则 notifyAll 的时候, 该线程从 wait 中被唤醒,
		// 但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能⼜已经队列满了
		// 就只能继续等待
			while (size == items.length) {
				wait();
			}
			items[tail] = value;
			tail = (tail + 1) % items.length;
			size++;
			notifyAll();
		}
	}
	
	public int take() throws InterruptedException {
		int ret = 0;
		synchronized (this) {
			while (size == 0) {
				wait();
			}
			ret = items[head];
			head = (head + 1) % items.length;
			size--;
			notifyAll();
		}
		return ret;
	}
	
	public synchronized int size() {
		return size;
	}
	
	// 测试代码
	public static void main(String[] args) throws InterruptedException {
		BlockingQueue blockingQueue = new BlockingQueue();
		Thread customer = new Thread(() -> {
		while (true) {
			try {
				int value = blockingQueue.take();
				System.out.println(value);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}, "消费者");	
	
		customer.start();
		Thread producer = new Thread(() -> {
			Random random = new Random();
				while (true) {					try {
						blockingQueue.put(random.nextInt(10000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}, "生产者");
			
		producer.start();
		customer.join();
		producer.join();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

Tee yhteenveto

  1. Estojono vastaa puskuria, joka tasapainottaa tuottajien ja kuluttajien prosessointivalmiuksia (huippujen leikkaus ja täyttö).
  2. Jonojen estäminen voi myös erottaa tuottajat ja kuluttajat.