`

线程间的协作关系与线程同步

 
阅读更多
1.线程间的协作关系
     当一个进程中的多个线程为完成同一任务而分工协作时,它们彼此之间有联系,知道其他线程的存在,而且受其他线程执行的影响。这些线程间存在协作关系,这是线程间的直接制约关系。由于合作的每一个线程都是独立地以不可预知的速度推进,这就需要相互协作的线程在某些协调点上协调各自的工作。当合作线程中的一个到达协调点后,在尚未得到其伙伴线程发来的信号之前应阻塞自己,直到其他合作线程发来协调信号后方被唤醒并继续执行。这种协作线程之间相互等待对方消息或信号的协调关系称为线程同步。
      例如:发送线程和接收线程。
本例演示传送数据的两个线程之间存在的协作关系,演示在没有实现线程同步运行时存在的错误。
     设计两个线程类:一个发送线程类Sender和一个接收线程类Receiver。两个线程对象并不能直接发送数据,它们必须约定一个存放数据的地方,通常称为缓冲区。所以,还要声明一个缓冲区类Buffer,缓冲区有一个成员变量value记录值,并提供对成员变量进行读/写操作的方法,发送线程调用put()方法设置value值,接收线程调用get()方法获得value值,如图所示:
         

package com.jbx.xiezuo;

public class Buffer {
	private int value; // 共享变量

	public int get() {
		return value;
	}

	public void put(int i) {
		this.value = i;
	}
	public static void main(String[] args) {
		Buffer buffer = new Buffer();
		(new Sender(buffer)).start();
		(new Receiver(buffer)).start();
	}
}

class Sender extends Thread { // 发送线程类
	private Buffer buffer; // 用于交换数据的共享变量

	public Sender(Buffer buffer) { // 指定缓冲区
		this.buffer = buffer;
	}

	public void run() {
		for (int i = 1; i < 6; i++) { // 连续向缓冲区发送若干数据
			buffer.put(i);
			System.out.println("Sender put: " + i);
			try {
				sleep(1);
			} catch (InterruptedException e) {

			}
		}
	}
}

class Receiver extends Thread { // 接收线程类
	private Buffer buffer;

	public Receiver(Buffer buffer) {
		this.buffer = buffer;
	}

	public void run() {
		for (int i = 1; i < 6; i++) { // 连续从缓冲区接收若干数据
			System.out.println("\t\t   Receiver get:" + buffer.get());
			try {
				sleep(1);
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
	}
	
}


某种运行结果:
Sender put: 1
   Receiver get:1
Sender put: 2
   Receiver get:2
Sender put: 3
   Receiver get:3
   Receiver get:4
Sender put: 4
Sender put: 5
   Receiver get:5

解析:虽然发送线程与接收线程每次休息的时间一样,但由于线程调度的不确定性,两个线程只是随机地交替执行,并不是步调一致地同步运行。此时,出现错误的原因并不是因为并发线程共享了缓冲区,而是因为它们访问缓冲区的速率不匹配。
       这两个线程必须协调一致地运行,每做一个操作,双方都要互通消息,发送线程必须在确定接收线程已接收到数据后,才能再次发送;接收线程每接收一个数据都要通知发送线程。这样才能确保数据传送的正确性。因此,协作线程间必须同步进行。

2.线程同步

       线程同步是解决线程间协作关系的手段。线程同步是指两个以上线程基于某个条件来协调它们的活动。一个线程的执行依赖于另一个线程线程的信号,当一个线程没有得到来自于另一个线程的信号时则需等待,直到信号到达才被唤醒。
        前述的线程互斥关系是一种特殊的线程同步关系,即逐次使用互斥共享资源,也是对线程使用资源次序上的一种协调。
3.线程同步机制
        操作系统中实现线程同步有一种工具称为信号量和PV操作,它的指导思想源于采用多种颜色信号灯管理交通的方法,描述如下:
(1)背景
     多个线程需要对同一个共享变量进行操作,所以多个线程间必须互斥地执行,即这些操作方法必须是互斥的。
(2)设置信号量
     为这个共享变量约定一个信号量(semaphore),设置信号量有多种状态,就像交通信号灯有多种颜色一样。信号量状态的设置有多种方式,既可以有两种状态,也可以有多种状态。两种状态用一个布尔值即可表示,true表示可执行,false表示不可执行,就像“红灯停,绿灯行”。多种状态表示一种轮流执行方式,如n为1时,约定线程1可执行;n为2时,约定线程2可执行,等等。
      测试信号量状态的操作称为P操作,改变信号量状态的操作称为V操作,这两种操作互斥执行的,并且执行时不能被打断。
(3)线程根据信号量状态而执行
     多个线程间彼此根据信号量的状态确定该谁执行,当一个线程开始执行时,它先要测试信号量的状态,如果状态合适,则执行,进行相关操作并更改信号量状态,唤醒其他等待线程执行;否则等待,使线程自己处于阻塞状态,直到被唤醒再次执行。
     这样,交互的并发线程之间通过交换信号来达到调整相互速率,保证线程协调运行的目的。利用信号量和P、V操作既可以解决并发进程的竞争问题,又可以解决并发进程的协作问题。

4.Java的线程通信方法
java.lang.Object 类提供wait()、notify()和notifyAll()方法实现线程间通信,方法声明如下:
public final void wait() throws InterruptedException  //等待
public final native void wait(long timeout) throws InterruptedException;//等待指定时间
public final native void notify();//唤醒一个等待线程
public final native void notifyAll();//唤醒所有等待线程
      这些方法可以被任意类的对象调用,并且声明为最终方法,不能被子类覆盖。一个对象调用wait()方法使当前执行线程变为等待状态,直到其他线程调用notify(),直到其他线程调用notify()或notifyAll()方法通知当前线程才停止等待,该线程被唤醒。
        wait(),notify()和notifyAll()方法提供线程间通信方法,对于线程同步问题,仅有这三个方法是不够的,还必须设置信号量及状态,约定对于共享变量的多种互斥操作方法。

  • 大小: 12 KB
分享到:
评论

相关推荐

    线程间同步和通信之事件(动态)

    本文将深入探讨如何利用RT-thread实时操作系统中的事件机制实现线程间的动态同步与通信。 RT-thread是一款开源、轻量级且功能强大的实时操作系统,适用于各种嵌入式设备。它提供了丰富的线程管理、内存管理、信号量...

    MFC线程间通信

    最后,线程同步法是一种更高级的线程间通信方式。MFC提供了各种同步对象,如事件对象(CEvent)、互斥量(CMutex)、信号量(CSemaphore)等。这些对象可以用来控制线程的执行顺序,确保关键资源的独占访问。例如,...

    linux上实现多进程和多线程实现同步互斥(源代码)

    - 使用条件变量实现线程间的协作,如生产者消费者模型。 - 实现读写锁,允许多个读取线程并行,写入线程独占。 - 应用信号量控制并发访问的资源数量。 总结,Linux上的多进程和多线程编程涉及复杂的同步互斥操作,...

    利用事件实现多线程同步

    然而,多线程也带来了一些问题,比如数据竞争、死锁等,这就需要我们采取措施进行线程同步。本主题将深入探讨如何利用事件(Event)来实现多线程同步。 事件(Event)是一种同步机制,它允许一个线程通过信号通知另一个...

    第20章 Part3 多线程互斥与协作.pdf

    ### 第20章 Part3:多线程互斥与协作 #### 一、互斥(Mutual Exclusion) 互斥是指在线程编程中确保多个线程不会同时访问同一资源的技术。这种技术非常重要,因为如果不加以控制,多个线程对共享资源的并发访问...

    Java中线程同步和线程协作学习笔记

    在Java编程中,线程同步和线程协作是多线程编程的重要概念,确保了在并发环境下程序的正确性和数据的一致性。线程同步的主要目标是解决线程安全问题,即在多线程访问共享资源时避免数据的混乱,保证程序的可再现性。...

    线程同步面试题深入解析

    线程同步是多线程编程中的关键概念,用于解决并发执行时可能出现的数据竞争问题,确保对共享资源的正确访问和管理。在Java中,线程同步主要通过`synchronized`关键字来实现,防止多个线程同时访问临界区,以避免出现...

    多线程的同步机制 VC++

    多线程同步机制在软件开发中扮演着至关重要的角色,特别是在多处理器系统或者并发执行的任务中,确保线程间的正确协作和数据一致性是必不可少的。VC++中提供了多种同步机制来处理多线程间的同步问题,其中Event是...

    创建多线程线程同步

    本主题将深入探讨如何在编程中创建多线程以及如何实现线程同步,特别关注CEVENT对象在Windows API中的应用。 **一、多线程的基本概念** 多线程是指在一个进程中可以同时运行多个独立的执行流,每个执行流被称为一...

    Jni多线程同步事例

    线程同步是指在多线程环境下,控制不同线程间执行的相对顺序,以避免数据竞争和其他并发问题。Java提供了多种同步机制,如synchronized关键字、Lock接口(如ReentrantLock)、Semaphore信号量等。 2. **JNI中的...

    多线程之间的线程通信

    3. **条件变量(Condition Variable)**:线程可以等待某个特定条件满足后才继续执行,这通常与锁结合使用,用于实现线程间的协作。 4. **管道(Pipe)**和**套接字(Socket)**:这些是进程间通信(IPC)的方法,也可以...

    c++ 多线程编程之三----线程间通讯

    线程间通讯可以让不同的线程之间进行信息传递,实现协作和同步。在多线程编程中,线程间通讯可以使用全局变量、自定义消息等方法来实现。 一、使用全局变量进行通信 在 C++ 中,使用全局变量可以实现线程间通讯。...

    传智播客_张孝祥_传统线程同步通信技术

    张孝祥老师的课程"传智播客_张孝祥_传统线程同步通信技术"深入浅出地讲解了这一主题,旨在帮助开发者理解和掌握线程间的协作与数据共享方式。 线程同步是指在多线程环境下,控制多个线程按一定的顺序执行,以避免...

    Java多线程机制和线程之间的协作

    Java提供了多种机制来实现线程同步,如synchronized关键字、wait()、notify()和notifyAll()方法。这些机制用于控制线程对共享资源的访问,防止数据不一致性和死锁的发生。守护线程(Daemon Thread)是一种特殊的线程...

    操作系统 线程同步和调度(源码)

    它可以是非递减信号量(互斥量的一种扩展)和递增信号量(用于线程间的协作)。 3. **条件变量(Condition Variables)**:条件变量允许线程等待满足特定条件后再继续执行。线程可以"等待"一个条件,当条件满足时,...

    Qt线程间通信,线程控制界面显示

    总结来说,“Qt线程间通信,线程控制界面显示”是通过巧妙利用Qt的信号与槽机制,实现后台线程和主线程的有效协作。它不仅提高了程序的运行效率,还保证了用户体验的流畅性。理解并熟练掌握这种通信方式,对于编写...

    创建线程及线程间通信

    线程通信是线程协作完成任务的关键,它允许线程之间交换数据或同步操作。一种常见的通信机制是“生产者-消费者”模型,其中生产者线程生成数据,而消费者线程消费这些数据。在没有适当的同步机制下,可能会出现数据...

    易语言线程暂停与继续

    - 在多线程协作中,暂停线程可以实现同步,防止数据冲突。 了解了这些基本概念后,你可以通过“线程暂停与继续”源码进一步学习易语言中线程操作的实践方法。这份源码可能包含了创建线程、挂起线程、恢复线程、...

    线程同步对象方法

    总之,线程同步是多线程编程中不可或缺的一部分,它帮助我们确保数据一致性,防止竞争状态,并允许线程间安全协作。在.NET中,通过Mutex、Monitor、lock、EventWaitHandle以及ReaderWriterLock等工具,开发者可以...

    多任务编程超入门-(9) 线程同步

    QT中的信号与槽机制是其核心特性,不仅用于线程间通信,还能用于线程同步。当一个对象发出信号时,可以触发其他对象的槽函数执行,这在多线程环境中可以用来协调不同线程的操作。例如,一个线程完成数据计算后发出...

Global site tag (gtag.js) - Google Analytics