lock和wait+signal

lock和wait+signal

在編程中,咱們常常使用多線程來提高性能,因此這就涉及到互斥和同步的問題了。而在編程中,咱們通常都是經過以下方式來完成多線程的互斥和同步:編程

  • lock | unlock
  • signal + wait(timeout)
  • join
  • sleep

C語言

在Linux C編程中,咱們一般使用pthread類庫來完成跨平臺的多線程控制,以下是幾個經常使用的API:多線程

  • pthread_mutex_lock():佔有互斥鎖(阻塞操做)
  • pthread_mutex_unlock(): 釋放互斥鎖
  • pthread_cond_signal(): 喚醒第一個調用pthread_cond_wait()而進入睡眠的線程
  • pthread_cond_wait(): 等待條件變量的特殊條件發生
  • pthread_cond_timedwait():等待條件變量的特殊條件發生或者timeout
  • pthread_join():阻塞當前的線程,直到另一個線程運行結束
  • sleep() : 休眠固定時間,不過這個API是Linux原生提供,不能跨平臺。

注意:**pthread類庫是glibc(絕大多數Linux平臺標準C庫。)的一部分。這些功能都是經過中斷號進入內核來完成的,而非僅僅作了Linux兼容API。**具體可見 glibc-2.23\sysdeps\nacl\nacl-interface-list.h ,聲明wait(timeout)功能中斷號文件。併發

Java

在Java中,多線程的控制已是一個統一標準了,通常都是經過Java原生API或者JUC來實現併發控制。這裏來講說原生的API:app

  • synchronized : 實現了lock 和 unlock的功能
  • Object#wait : 等待信號發生,而且能夠實現超時等待
  • Object#notify : 通知信號發生
  • Object#notifyAll :通知信號發生
  • Thread#join :阻塞當前的線程,直到另一個線程運行結束
  • Thread#sleep : 休眠固定時間

經過這些API,咱們基本上能實現Java的多線程併發控制,固然了可使用最新的JUC併發庫的API。而這些API底層也是能夠經過pthread這個C庫來實現。ide

示例-Timer

Java中Timer的實現原理就是經過 wait 和 notify 以及 synchronized 來實現的:性能

Timer timer = new Timer();
timer.schedule(new TimerTask() {
	@Override
	public void run() {

	}
}, 1000);

其實,Timer持有TimerImpl,其實Impl就是一個Thread實現,它一直阻塞等待task的到來,見run代碼:this

public void run() {
	while (true) {
		TimerTask task;
		synchronized (this) {
			// need to check cancelled inside the synchronized block
			if (cancelled) {
				return;
			}
			//等待任務
			if (tasks.isEmpty()) {
				if (finished) {
					return;
				}
				// no tasks scheduled -- sleep until any task appear
				try {
					//等待任務加入後,會經過notify來通知它能夠運行
					this.wait();
				} catch (InterruptedException ignored) {
				}
				continue;
			}
			....
			if (timeToSleep > 0) {
				// sleep!
				try {
					//延遲執行代碼
					this.wait(timeToSleep);
				} catch (InterruptedException ignored) {
				}
				continue;
			}

			// no sleep is necessary before launching the task
			...
		}

		...
		try {
			//具體執行任務
			task.run();
			taskCompletedNormally = true;
		} finally {
			...
		}
	}
}

能夠看到TimerImpl的run代碼會經過wait來阻塞等待任務加入queue,而後經過notify告知它能夠運行task。timer#schedule最後會調用TimerImpl#insertTask,具體代碼以下:線程

private void insertTask(TimerTask newTask) {
	// callers are synchronized
	tasks.insert(newTask);
	this.notify();
}

**因此任務加入隊列後,經過notify來告知阻塞在等待任務的線程(TimerImpl#run)。**這樣子就實現了Timer的功能了,而且經過wait(timeout)實現了delay的功能。code

總結

多線程的控制,其實大多都是依賴:orm

  • lock
  • signal + wait

這兩種類型的API來完成併發控制。

而在此基礎上,咱們能夠實現各類各樣的多線程併發控制,好比說:MQ,CountDownLatch等。

相關文章
相關標籤/搜索