首先,简单了解三个概念
程序: 静态描述怎么运行的文本,可以说是指令集合
进程: 是具有一定独立功能的程序关于某个数据集合上的一次运行活动。(官方解释)
是系统进行资源分配和调度的一个独立单位.
线程:进程中单一顺序的控制流。也可以说是轻量级进程。目前程序执行的最小单元。
是CPU调度和分派的基本单位.他不拥有自己的资源,但共享进程的资源.
【程序】没有资源不能独立运行起来,所以产生了【进程】。一个程序可以有多个进程。
【进程】同一时间不能完全大量的工作,所以将自己分流程了【线程】。一个进程可以有多个线程。
【线程】划分到很细了,他的优点:提高了进程的并发度,有效利用多处理机和多和计算机。
①、线程是指进程内的一个执行单元,也是进程内的可调度实体.
②、进程有自己的独立地址空间,进程之间资源不共享。线程因为是一个进程分流下来,所以共享资源。(本质区别)
③、线程是处理器调度的基本单位。
④、进程的并发执行属于处理器上的抽象,线程的并发执行则是比进程更深一层的抽象。
简而言之,
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
为什么使用多线程:
这个不多说了.....总之就是忙到你想要三头六臂时,他就出现了.
优点:
1.繁忙的处理或计算一些大数据时,为了保证主线程不一直等待,这种应该交给后台的线程去做.
2.使资源得到最优化分配.
3.缩短完成任务的时间
缺点:
1.操作系统需要切换线程,所以大量使用反而变得更慢
2.线程多了,BUG也多了
3.需要更大的内存空间
4.保证程序的安全性(死锁,中止).
使用线程:
C/C++
include<thread>; //线程的类都在这里
void threadFunc()
{ //线程内容
std::cout<<"hello world";
}
int main()
{
std::thread t1=(threadFunc); //启动线程
t1.join(); //保证t1执行完毕才主线程才能关闭.
return 0;
}
也可以使用λ方式写,总之线程的开源代码:
http://www.oschina.net/question/12_45346
JAVA
第一种方法: 继承thread类
class MyThread extends Thread{
public void run() { //线程内容 }
}
public static void main( String[ ] args ){
( new MyThread( ) ).start(); //启动线程
}
第二种方法: 用Runnable接口 (一般用这种,因为继承只能继承一种,但能对很多种接口
class MyThread implents Runnable{
public void run() { //线程内容 }
}
public static void main( String[ ] args ){
( new thread( new MyThread( ) ) ).start(); //启动线程
}
android
通常创建线程是使用JAVA的上面两种的结合版.
不用继承thread,也不用实现runnable接口直接实例化一个thread,实现runnable的匿名内部类
Thread mThread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
//线程内容
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
mThread.start();
安卓的多线程还需要涉及的技术有:handler,Message,MessageQueue,Looper,HandlerThread
在主线程定义handler来对消息进行反应,有Message 和 Post 两种写法
Message写法是要重载handleMessage函数
//Looper.preper(); 初始化Looper
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0://内容
}
}
};
//Looper.loop(); 启动消息队列
头尾两句只有在子线程中才需要,UI线程中已有消息队列不用绑定了.
在子线程中发送消息
Message message = new Message();
message.obj = timer;
message.what = 0;
handler.sendMessage(message);
POST写法,直接在子线程发送一个runnable,然后主线程中执行
handler.post(new Runnable() {
@Override
public void run() {
tvMessage.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");
}
});
同步与互斥
用户模式:原子操作,临界区
内核模式:事件,信号量,互斥量
原子操作
不可分割的一个指令,一执行就做到结束为止,不可中断.
临界区
EnterCriticalSection() 进入临界区
LeaveCriticalSection() 离开临界区
两个对应着出现.保证单个线程访问数据,其他试图进入的线程将被挂起,直到之前的离开临界区.
实现同进程的线程同步
事件
使用通知的方式,实现不同进程的线程同步
CreateEvent() 创建一个信号量
OpenEvent() 打开一个事件
SetEvent() 回置事件
WaitForSingleObject() 等待一个事件
WaitForMultipleObjects() 等待多个事件
WaitForMultipleObjects 函数原型:
WaitForMultipleObjects(
IN DWORD nCount, // 等待句柄数
IN CONST HANDLE *lpHandles, //指向句柄数组
IN BOOL bWaitAll, //是否完全等待标志
IN DWORD dwMilliseconds //等待时间
)
互斥量
每两个线程成互斥,互斥对象只有一个,所以保证数据访问的安全.而且能跨进程实现.
CreateMutex() 创建一个互斥量
OpenMutex() 打开一个互斥量
ReleaseMutex() 释放互斥量
WaitForMultipleObjects() 等待互斥量对象
信号量
PV操作..,S可以设置初始值,即允许最大有多少个线程访问.
P申请空间:S-1
V释放空间S+1
CreateSemaphore() 创建一个信号量
OpenSemaphore() 打开一个信号量
ReleaseSemaphore() 释放信号量
WaitForSingleObject() 等待信号量
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
volatile int ThreadData = 1;
CRITICAL_SECTION csPrint; // 临界区
//HANDLE evtPrint; // 事件信号,标记事件是否已发生
//HANDLE mtxPrint; // 互斥信号,如有信号表明已经有线程进入临界区并拥有此信号
//HANDLE smphPrint; // 信号量,表示是否已经达到允许的最大线程数
void Print(char *str)
{
EnterCriticalSection(&csPrint); // 进入临界区
//WaitForSingleObject(evtPrint, INFINITE); // 等待事件有信号
//WaitForSingleObject(mtxPrint, INFINITE); // 等待互斥量空置(没有线程拥有它)
//WaitForSingleObject(smphPrint, INFINITE); // 等待对共享资源请求被通过 等于 P操作
for (;*str != '\0';str++)
{
Sleep(50);
printf("%c",*str);
}
printf("\n");
LeaveCriticalSection(&csPrint); // 退出临界区
//SetEvent(evtPrint); // 把事件信号量恢复,变为有信号
//ReleaseMutex(mtxPrint); // 释放对互斥量的占有
//ReleaseSemaphore(smphPrint, 1, NULL); // 释放共享资源 等于 V操作
}
void ThreadProcess()
{
for(int i=0; i<6; i++)
{
Sleep(1000);
Print("Sub Thread is running!");
}
ThreadData = 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread;
DWORD ThreadID;
InitializeCriticalSection(&csPrint); // 初始化临界区
//evtPrint = CreateEvent(NULL, FALSE, TRUE, L"PrintEvent"); // 初始化事件
//mtxPrint = CreateMutex(NULL, FALSE, L"PrintMutex"); // 初始化互斥量
//smphPrint= CreateSemaphore(NULL, 1, 1, L"PrintSemaphore"); // 设置信号量1个资源,因此同时只可以有一个线程访问
hThread=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadProcess,
NULL,
0,
&ThreadID);
while (ThreadData)
{
Print("Main Thread is waiting for Sub Thread!");
Sleep(600);
}
printf("Main Thread Finished!");
system("pause");
return 0;
}