Κοινή χρήση τεχνολογίας

[Λειτουργικό σύστημα] Μπλοκάρισμα ουράς και μοντέλο παραγωγού-καταναλωτή

2024-07-12

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

ουρά αποκλεισμού

1. Έννοια

Η ουρά αποκλεισμού είναι ένα ειδικό είδος ουράς Ακολουθεί επίσης την αρχή "πρώτος μέσα, πρώτος έξω".

Η ουρά αποκλεισμού μπορεί να είναι μια δομή δεδομένων ασφαλής για νήματα και έχει τα ακόλουθα χαρακτηριστικά:

  • Όταν η ουρά γεμίσει, η συνέχιση της εισαγωγής στην ουρά θα αποκλειστεί έως ότου άλλα νήματα πάρουν στοιχεία από την ουρά..
  • Όταν η ουρά είναι άδεια, η συνέχιση της ουράς θα μπλοκάρει επίσης έως ότου άλλα νήματα εισαγάγουν στοιχεία στην ουρά.

Ένα τυπικό σενάριο εφαρμογής αποκλεισμού ουράς είναι το "μοντέλο παραγωγού-καταναλωτή" Αυτό είναι ένα πολύ τυπικό μοντέλο ανάπτυξης
παραγωγός

Το καταναλωτικό μοντέλο επιλύει το πρόβλημα ισχυρής σύζευξης μεταξύ παραγωγών και καταναλωτών μέσω ενός εμπορευματοκιβωτίου.

Οι παραγωγοί και οι καταναλωτές δεν επικοινωνούν απευθείας μεταξύ τους, αλλά επικοινωνούν μέσω ουρών αποκλεισμού. Επομένως, αφού ο παραγωγός παράγει τα δεδομένα, δεν χρειάζεται να περιμένει να τα επεξεργαστεί ο καταναλωτής, αλλά τα ρίχνει απευθείας στην ουρά αποκλεισμού Δεν ζητά δεδομένα από τον παραγωγό, Αντίθετα, λαμβάνονται απευθείας από την ουρά αποκλεισμού.

Υπάρχουν δύο βασικά βήματα στην εφαρμογή του μοντέλου παραγωγού-καταναλωτή:

  1. παραγωγός υλικών
  2. συνειδητοποιήσει τον καταναλωτή

2. Αποκλεισμός ουράς στην τυπική βιβλιοθήκη

Υπάρχει μια ουρά αποκλεισμού ενσωματωμένη στην τυπική βιβλιοθήκη Java Εάν πρέπει να χρησιμοποιήσουμε ουρές αποκλεισμού σε ορισμένα προγράμματα, μπορούμε να χρησιμοποιήσουμε απευθείας την ουρά αποκλεισμού στην τυπική βιβλιοθήκη.
Μπορώ.

  • Το BlockingQueue είναι μια διεπαφή Η πραγματική κλάση υλοποίησης είναι το LinkedBlockingQueue
  • Η μέθοδος put χρησιμοποιείται για τον αποκλεισμό της εισόδου στην ουρά και η μέθοδος λήψης χρησιμοποιείται για τον αποκλεισμό της εξόδου από την ουρά.
  • Το BlockingQueue έχει επίσης μεθόδους όπως προσφορά, δημοσκόπηση και peek, αλλά αυτές οι μέθοδοι δεν έχουν χαρακτηριστικά αποκλεισμού.

Ο ψευδοκώδικας για την ουρά αποκλεισμού είναι ο εξής:

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

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

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

3. Μοντέλο παραγωγού-καταναλωτή

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. Αποκλεισμός υλοποίησης ουράς

  1. Αυτό επιτυγχάνεται με τη μέθοδο της «κυκλικής ουράς».
  2. Χρησιμοποιήστε το συγχρονισμένο για έλεγχο κλειδώματος.
  3. Όταν το put εισάγει στοιχεία, καθορίζει εάν η ουρά είναι πλήρης και περιμένει (Λάβετε υπόψη ότι η αναμονή πρέπει να εκτελείται σε βρόχο. Όταν αφυπνίζεται, η ουρά μπορεί να μην είναι γεμάτη επειδή μπορεί να ενεργοποιηθούν πολλά νήματα ταυτόχρονα. ).
  4. Όταν αφαιρεί το στοιχείο, καθορίζει εάν η ουρά είναι κενή και περιμένει (είναι επίσης μια αναμονή βρόχου).
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

Συνοψίζω

  1. Η ουρά αποκλεισμού είναι ισοδύναμη με ένα buffer, εξισορροπώντας τις δυνατότητες επεξεργασίας των παραγωγών και των καταναλωτών (Peak clipping and filling).
  2. Ο αποκλεισμός των ουρών μπορεί επίσης να αποσυνδέσει παραγωγούς και καταναλωτές.