本文目录
- JAVA线程间通信的几种方式
- 线程间通信有哪些机制
- 什么是线程通信
- 两线程间相互通信如何实现
- 线程的几种控制方式以及线程间的几种通信方式
- 进程间通信和线程间通信的区别
- 线程间通信有哪些方式
- java中怎么实现线程通信
- windows怎么实现线程间的通信
- 如何在学习Java过程中实现线程之间的通信
JAVA线程间通信的几种方式
Java多线程间的通信
Java还提供了一种线程间通信的机制,这种通信通什么实现?
wait,notify等机制
或使用pipeInputStream和pipeOutputStream
1. 线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。
线程间通信有哪些机制
机制?您是问有什么方法么?
1.
可以通过启动线程前传递的
object
对象传递数据(线程启动的时候可以接收一个
object
对象)。
2.
通过委托传递数据(大多是子线程操作主线程的时候用到)。
3.
通过静态的通用变量或属性传递(建个静态的变量或属性,将要传递的数据写在它上面,然后另一个线程在去这个变量或属性中读取这个值)。
什么是线程通信
多线程通信的方法主要有以下三种:
1.全局变量
进程中的线程间内存共享,这是比较常用的通信方式和交互方式。
注:定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。
2.Message消息机制
常用的Message通信的接口主要有两个:PostMessage和PostThreadMessage,
PostMessage为线程向主窗口发送消息。而PostThreadMessage是任意两个线程之间的通信接口。
2.1.PostMessage()
函数原型:
B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
参数:
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口
和弹出式窗口。消息不被寄送到子窗口。
NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。
MS还提供了SendMessage方法进行消息间通讯,SendMessage(),他和PostMessage的区别是:
SendMessage是同步的,而PostMessage是异步的。SendMessage必须等发送的消息执行之后,才返回。
2.2.PostThreadMessage()
PostThreadMessage方法可以将消息发送到指定线程。
函数原型:BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam, LPARAM lParam);
参数除了ThreadId之外,基本和PostMessage相同。
目标线程通过GetMessage()方法来接受消息。
注:使用这个方法时,目标线程必须已经有自己的消息队列。否则会返回ERROR_INVALID_THREAD_ID错误。可以用
PeekMessage()给线程创建消息队列。
3.CEvent对象
CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步。
-线程通信
两线程间相互通信如何实现
管道流是为也实现多个线程之间的I/O通信。用于在一个(或多个)线程发送数据,另一个线程(或多个)接收数据。这也类似于Producer/Consumer模式。它可以用于实现unix下的管道,只不过是unix下管道连接的是进程,而java下连接的是线程。
-线程
线程的几种控制方式以及线程间的几种通信方式
几种进程间的通信方式
(1) 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。
(2)有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
(3)信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(4)消息队列(message queue):消息队列是由消息组成的链表,存放在内核中 并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。
(6)共享内存(shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他进程间的通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。
(7)套接字(socket):套接口也是一种进程间的通信机制,与其他通信机制不同的是它可以用于不同及其间的进程通信。
几种线程间的通信机制
1、锁机制
1.1 互斥锁:提供了以排它方式阻止数据结构被并发修改的方法。
1.2 读写锁:允许多个线程同时读共享数据,而对写操作互斥。
1.3 条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
2、信号量机制:包括无名线程信号量与有名线程信号量
3、信号机制:类似于进程间的信号处理。
线程间通信的主要目的是用于线程同步,所以线程没有象进程通信中用于数据交换的通信机制。
-线程通信
进程间通信和线程间通信的区别
只有进程间需要通信,同一进程的线程share地址空间,没有通信的必要,但要做好同步/互斥mutex,保护共享的全局变量。线程拥有自己的栈。同步/互斥是原语primitives.
而进程间通信无论是信号,管道pipe还是共享内存都是由操作系统保证的,是系统调用.
-线程
线程间通信有哪些方式
线程间通信方式有:
1、volatile
volatile有两大特性,一是可见性,二是有序性,禁止指令重排序,其中可见性就是可以让线程之间进行通信。volatile语义保证线程可见性有两个原则保证:
(1)所有volatile修饰的变量一旦被某个线程更改,必须立即刷新到主内存。
(2)所有volatile修饰的变量在使用之前必须重新读取主内存的值。
2、等待/通知机制
等待通知机制是基于wait和notify方法来实现的,在一个线程内调用该线程锁对象的wait方法,线程将进入等待队列进行等待直到被通知或者被唤醒。
3、join方式
join其实合理理解成是线程合并,当在一个线程调用另一个线程的join方法时,当前线程阻塞等待被调用join方法的线程执行完毕才能继续执行,所以join的好处能够保证线程的执行顺序。
但是如果调用线程的join方法其实已经失去了并行的意义,虽然存在多个线程,但是本质上还是串行的,最后join的实现其实是基于等待通知机制的。
4、threadLocal
threadLocal方式的线程通信,不像以上三种方式是多个线程之间的通信,它更像是一个线程内部的通信,将当前线程和一个map绑定,在当前线程内可以任意存取数据,减省了方法调用间参数的传递。
线程特点:
1、轻型实体
线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。线程的实体包括程序、数据和TCB。线程是动态概念,它的动态特性由线程控制块TCB(Thread Control Block)描述。-线程通信
2、独立调度和分派的基本单位
在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(在同一进程中的)。
3、可并发执行
在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;同样,不同进程中的线程也能并发执行,充分利用和发挥了处理机与外围设备并行工作的能力。
4、共享进程资源
在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址。
此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
java中怎么实现线程通信
线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务。
Object类中相关的方法有两个notify方法和三个wait方法:
因为wait和notify方法定义在Object类中,因此会被所有的类所继承。
这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。
wait()方法
wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
当前的线程必须拥有当前对象的monitor,也即lock,就是锁。
线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
-线程
windows怎么实现线程间的通信
Windows线程间通信
.
1.概述
如果一个进程中的所有线程都不需要相互传递数据就可以顺利完成,那么程序运行的性能自然是最好的,但是实际上,很少有现成能够在所有的时间都独立的进行操作,通常在以下两种情况下,线程之间需要进行通信。
a) 多个线程都对共享资源资源进行访问,但不希望共享资源被破坏。
b) 一个线程完成了任务,要通知其他的线程。
情况a)属于互斥问题,情况b)属于同步问题。通常的解决方法如下:
2.解决方法
a) 互锁函数
互锁函数是windows提供的一个函数族,它可以实现对共享变量的简单原子访问,所谓的原子访问就是说当当前线程正在访问资源时,可以保证其他的线程没有同时访问这个资源。但是它只能完成以原子操作方式修改单个值,作用域很小。
Eg:
Long g = 0;
DWORD _stdcall TF1(PVOID p){
g++;
Return 0;
}
DWORD _stdcall TF2(PVOID p){
g++;
Return 0;
}
在上面的例子中,不能保证运行结束时g的值为2,因为在自加的过程中,线程可能会被另一个线程打断,这时,两个线程可能对同一个变量进行了操作,出现了错误,这是使用互锁函数改为即可保证在一个线程进行g++时,另一个线程不会将其打断。
Long g = 0;
DWORD _stdcall TF1(PVOID p){
InterlockedExchangeAdd(&g, 1);
Return 0;
}
DWORD _stdcall TF2(PVOID p){
InterlockedExchangeAdd(&g, 1);
Return 0;
}
类似的函数还有
LONG InterlockedExchange(PLONG plTarget, LONG lValue);
PVOID InterlockedCompareExchange(PLONG plDestination, LONG lExchange, LONG lComparand);
b) 临界段
临界段也叫做关键代码段,它是一小段代码,通过设置临界区域,能够以原子操作的方式使用资源。具有相同临界资源的临界段只能允许一个线程执行它,其他要进入该段的线程将被挂起,直到前面的线程释放临界资源。
Win32 API中临界段的设置:
首先定义一个全局临界对象,类型为CRITICAL_SECTION
CRITICAL_SECTION cs;
然后调用函数对其初始化:
InitializeCriticalSection(&cs);
这样就创建了一个名为cs的临界段对象了,然后对于可能会发生冲突的线程代码段使用同一个临界对象进行处理即可,进入临界段的代码为:
EnterCriticalSection(&cs);
此时,线程被认为拥有临界段对象,没有两个线程可以同时拥有相同的临界对象,因此,如果一个线程进入了临界段,那么下一个使用相同临界段对象调用EnterCriticalSection的线程将被挂起。离开临界段的函数为:
LeaveCriticalSeciton(&cs);
此时,释放临界对象的所有权,删除临界对象的函数为:
DeleteCriticalSection(&cs);
c) 使用内核对象进行线程通信
互锁函数和临界段都是属于用户态的通信,好处是速度很快,但是对许多应用程序而言是不足的,而使用内核对象进行通信速度较慢,其他的性能较好。使用内核对象进行线程通信的机理是:很多内核对象存在一个属性,用来表示该内核对象是已通知状态还是未通知状态,然后通常使用WaitForSingleObject或WaitForMultipleObjects来等待特定内核对象的已通知状态。
事件对象
事件内核对象通常和WaitForSingleObject等联合使用,事件对象主要用于标志一个操作是否已经完成,其函数为:
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL fManualReset,
BOOL fInitialState,
PCTSTR pszName);
第一个参数为安全属性,第二个参数用于设置创建一个人工重置事件(ture)还是自动重置事件,两者的区别在于:如果设置成人工重置事件,则需要使用SetEvent和ResetEvent函数来将事件设置成已通知事件和未通知事件,当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度的;如果设置成自动重置事件,当使用SetEvent设置事件的通知状态时,在等待事件的线程中,只有一个线程被回复(哪个不确定),之后系统自动将事件设为未通知状态。第三个参数用于设置事件初始状态,第四个参数用于设置事件的名字。
互斥对象
互斥量是一种内核对象,它能够确保线程拥有对单个资源的互斥访问权。它与临界段相同,但是互斥量属于内核对象,临界段属于用户对象,这意味着互斥要比临界段慢,但是不同进程中的多个线程能够访问单个互斥量。互斥量不同于所有其他的内核对象,互斥量中有一个线程ID,用于标志该互斥量属于哪个线程(即不论在哪个线程中创建了没有归属的互斥量,只要在某个线程中将互斥量变为未通知事件,那么这个线程就拥有这个互斥量,如果在该线程中释放了这个互斥量,那么该互斥量又变成游离状态,没有所属的线程,然后重复上面的过程),因此互斥量有一个“线程所有权”的概念,因此如果调用ReleaseMutex的线程不拥有互斥量,那么该函数不进行任何操作。
Win32 API互斥量函数:
创建一个互斥量:
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL fInitialOwner,
PCTSTR pszName);
第一个参数安全属性,最后一个参数为互斥量的名字,第二个参数:
A) 如果设为FALSE,则表示没有线程拥有该互斥量,线程ID为0,处于已通知 状态。
B) 如果设为TURE,则表示当前线程拥有该互斥,线程ID为当前线程的ID,处 于未通知状态。
当某个拥有互斥的线程不想再拥有该互斥的时候,则调用函数:
ReleaseMutex(HANDLE hMutex);
来释放该线程对该互斥的占有,此后该互斥量又变成游离的状态,直到再出现一个 线程拥有它。
信号量
信号量也是一种内核对象,用于对资源进行计数。信号量的使用规则是:如果当前资源数量大于0,那么等待信号量的线程可以获得一个资源并继续执行,信号量的当前资源数将减1;如果当前资源数为0,那么等待信号量的线程将处于等待状态,直到有线程释放信号量,使当前资源数大于0,当前资源数不会超过最大资源数量值,也不会小于0。
Win32用于创建和释放信号量的API函数
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTE psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);
BOOL ReleaseSemaphore(
HANDLE hsem,
LONG lReleaseCount,
PLONG plPreviousCount);
参考链接: http://dev.yesky.com/339/2292339.shtml
-线程通信
如何在学习Java过程中实现线程之间的通信
在java中,每个对象都有两个池,锁池(monitor)和等待池(waitset),每个对象又都有wait、notify、notifyAll方法,使用它们可以实现线程之间的通信,只是平时用的较少.
wait(): 使当前线程处于等待状态,直到另外的线程调用notify或notifyAll将它唤醒
notify(): 唤醒该对象监听的其中一个线程(规则取决于JVM厂商,FILO,FIFO,随机…)
notifyAll(): 唤醒该对象监听的所有线程
锁池: 假设T1线程已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用该对象的synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前都需要先获得该对象的锁的拥有权,但是该对象的锁目前正被T1线程拥有,所以这些线程就进入了该对象的锁池中.-线程
等待池: 假设T1线程调用了某个对象的wait()方法,T1线程就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前T1线程就已经拥有了该对象的锁),同时T1线程进入到了该对象的等待池中.如果有其它线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,从新争夺锁的拥有权.如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.-线程通信
java实现线程间通信的四种方式
1、synchronized同步:这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。
2、while轮询:其实就是多线程同时执行,会牺牲部分CPU性能。
3、wait/notify机制
4、管道通信:管道流主要用来实现两个线程之间的二进制数据的传播