JAVA基础篇七(Java,C++中的线程)

讲到线程,Java的线程目前只知道从thread继承,并用start函数启动线程,稍后会多了解JAVA线程相关知识,补充到这一章中。

C++的线程在读硕期间用到过多次,下面首先总结一下:

1、C++线程

(1)MFC多线程

这种方式我没用过,所以这里只是提一下,主要在MFC中,一般用全局函数AfxBeginThread()来创建并初始化一个线程的运行,该函数有两种重载形式,分别用于创建工作者线程和用户界面线程。

(2)phtread

POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac
OS X等)中,都使用Pthreads作为操作系统的线程。Windows操作系统也有其移植版pthreads-win32。

利用phread编写的程序可以跨平台执行,Pthread的使用方式可以参考博主这篇文章:http://blog.csdn.net/feiyangtianyao/article/details/23368969

Pthread的简单使用

在一个要求使用多线程的项目中,一般使用Phread的情况下,下面几个函数即可完成任务:

pthread_t:线程ID

pthread_create():创建一个线程

pthread_exit():终止当前线程

pthread_cancel():中断另外一个线程的运行

pthread_join():阻塞当前的线程,直到另外一个线程运行结束

pthread_kill():向线程发送一个信号

pthread_mutex_init() 初始化互斥锁

pthread_mutex_destroy() 删除互斥锁

pthread_mutex_lock():占有互斥锁(阻塞操作)

pthread_mutex_unlock(): 释放互斥锁

pthread_self(): 查询线程自身线程标识号

pthread_equal(): 对两个线程的线程标识号进行比较

示列代码(VS 已卸,代码是拷贝的):

#include <iostream>
#include <pthread.h> //多线程相关操作头文件,可移植众多平台

using namespace std;

#define NUM_THREADS 5 //线程数

void* say_hello( void* args )
{
    cout << "hello..." << endl;
} //函数返回的是函数指针,便于后面作为参数

int main()
{
    pthread_t tids[NUM_THREADS]; //线程id
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        int ret = pthread_create( &tids[i], NULL, say_hello, NULL ); //参数:创建的线程id,线程参数,线程运行函数的起始地址,运行函数的参数
        if( ret != 0 ) //创建线程成功返回0
        {
            cout << "pthread_create error:error_code=" << ret << endl;
        }
    }
    pthread_exit( NULL ); //等待各个线程退出后,进程才结束,否则进程强制结束,线程处于未终止的状态
}

更多详细介绍可以参考转载的这篇文章:http://blog.csdn.net/feiyangtianyao/article/details/28625821

(3)OpenMP

OpenMP是一种简单的多线程工具,OpenMP的细粒度并行特性,使其常被用于高性能计算中。

OpenMP的使用简单,在windows下只需设置菜单栏->Project->Properties,弹出菜单里,点击 Configuration Properties->C/C++->Language->OpenMP Support,在下拉菜单里选择Yes。

在Linux下,利用命令gcc/g++ -fopenmp 即可。

如果你只想用OpenMP简单实现多线程的开发,那么以下命令即可实现:

#pragma omp parallel for;实现for循环的并行计算;

#pragma omp parallel sections,#pragma omp section;代码块的并行计算。

#pragma omp task 显式创建任务。

#pragma omp single 选中某个线程执行接下来的语句;

#pragma omp master选择0号线程执行接下来的语句。

#pragma omp barrier显式栅障,所有线程执行到此处等待。

omp_get_num_procs()得到CPU核心数;

omp_get_num_threads()得到OpenMP的线程数,OpenMP的线程数可以在程序中手动设置。

omp_get_wtime()得到当前时间,单位是s, 通常利用两个时间取程序的执行时间,这个时间是程序运行时间,不是总的CPU时间。

omp_init_lock(omp_lock *)          初始化互斥器

omp_destroy_lock(omp_lock *)       销毁互斥器

omp_set_lock(omp_lock *)           获得互斥器

omp_unset_lock(omp_lock *)         释放互斥器

omp_test_lock(omp_lock *)          试图获得互斥器,如果获得成功返回true,否则返回false

由于OpenMP设计的初衷是高性能并行计算,因此,锁操作的使用应当尽量避免,可以使用显式并行或者改造程序结构的方法避免锁的频繁使用。

OpenMP中还有其他需要条件关键字的使用,例如private,firstprivate,lastprivate等,这里不再详细说明。可以参考OpenMP的官方文档。

常常利用if(i==omp_get_thread_num())来控制单个线程的执行情况。

代码示列(拷贝别人的,这么简单的东西,就当熟悉一下):

#include <iostream>
#include <omp.h>
int main(){
    int sum = 0;
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
    int coreNum = omp_get_num_procs();//获得处理器个数
    int* sumArray = new int[coreNum];//对应处理器个数,先生成一个数组
    for (int i=0;i<coreNum;i++)//将数组各元素初始化为0
        sumArray[i] = 0;
#pragma omp parallel for
    for (int i=0;i<10;i++)
    {
        int k = omp_get_thread_num();//获得每个线程的ID
        sumArray[k] = sumArray[k]+a[i];
    }
    for (int i = 0;i<coreNum;i++)
        sum = sum + sumArray[i];
    std::cout<<"sum: "<<sum<<std::endl;
    return 0;
}

C++中也有其他多线程工具,比如Cilk,CUDA(GPU的线程)。

2、JAVA线程

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口和Executor框架。

http://blog.csdn.net/aboy123/article/details/38307539这篇文章讲的很清楚了,没必要献丑了,这里只做一个简介吧。

(1)继承Thread类实现多线程

继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法

(2)实现Runnable接口实现多线程

在我们刚接触的时候可能会迷糊继承Thread类和实现Runnable接口实现多线程,其实在接触后我们会发现这完全是两个不同的实现多线程,一个是多个线程分别完成自己的任务,一个是多个线程共同完成一个任务。

其实在实现一个任务用多个线程来做也可以用继承Thread类来实现只是比较麻烦,一般我们用实现Runnable接口来实现,简洁明了。

大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类(Thread)创建子类。

具体讲解参照:http://mars914.iteye.com/blog/1508429

(3)Executor框架

Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-18 22:09:17

JAVA基础篇七(Java,C++中的线程)的相关文章

Java基础篇Socket网络编程中的应用实例

说到java网络通讯章节的内容,刚入门的学员可能会感到比较头疼,应为Socket通信中一定会伴随有IO流的操作,当然对IO流比较熟练的哥们会觉得这是比较好玩的一章,因为一切都在他们的掌握之中,这样操作起来就显得非常得心应手,但是对于IO本来就不是多熟悉的哥们来说就有一定的困难了,在搞清楚IO流操作机制的同时还必须会应用到Socket通信中去,否则会对得到的结果感到非常郁闷和懊恼,下面就和大家一起分享一下自己遇到一点小麻烦后的感触以及给出的解决办法. 要求:客户端通过Socket通信技术上传本地一

java基础篇(三) ----- java面向对象的三大特性之多态

封装(encapsulation) 类使得数据和对数据的操作捆绑在一起,从而对使用该类的其他人来说,可以不管它的实现方法,而只管用它的功能,从而实现所谓的信息隐藏: 继承(inheritance) 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类.这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用.比如可以先定义一个类叫animal,animal具有以下属性:   眼睛,鼻子,耳朵 而又由ani

java基础篇(二) ----- java面向对象的三大特性之继承

java面向对象的三大特性之继承: 复用代码是java众多引人注目的功能之一,但是想要成为极具革命性的语言,仅仅是复制代码并对其加以改变是不够的.它必须能够做更多的事.引自<Think in java>    而代码复用也是程序员一直不断追求的.由此来说下代码复用的一种方式 java面向对象的三大特性--继承!! 在面向对象程序设计中,继承机制可以有效地组织类的结构.确定类之间的关系,在已有类的基础上开发新的类.继承机制在程序代码复用.提高软件开发效率.降低软件系统维护成本等方面具有重要作用.

java基础篇(一) ----- java面向对象的三大特性之封装

java面向对象的三大特性之封装:   封装(Encapsulation)是面向对象的一个重要特征,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节. 通俗的讲所谓封装就是将属性和方法捆绑到一起,封装到一个对象中去, 形成一个不可分割的独立单位,以及尽可能隐藏对象的内部结构,也就是说,如果我们使用了封装技术的话,别人就只能用我们做出来的东西而看不见我们做的这个东西的内部结构了. 如果形容一个人(假设把人看做一个类),我们可以用姓名.年龄,性别等来描述,如果不封

java基础篇---I/O技术(三)

接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream).使用对象输出流输出序列化对象的步骤,有时也成序列化,而使用对象输入流读入对象的过程,有时也称为反序列化 一个对象产生之后实际上是在内存中为其开辟了一个存储空间,方便存储信息. 对象序列化就是把一个对象变成二进制的数据流的一个方法,通过对象序列化可以反驳的

[Java 05 OO] (基础篇) 《Java开发实战经典》

p5OO 第五章 面向对象 (基础篇) Notes (1), Constructor / this / String   String str1 = "hello"; 解释 : 是把一个在堆内存空间的使用权给了 str1 对象.   String str2 = "hello"; str1 == str2 是 true   String 字符串的内容不可改变 (2), Java 常用的内存区域    1), 栈内存空间    2), 堆内存空间    3), 全局数据

复习java基础第七天(反射)

一:目标 Ø理解 Class 类 Ø理解 Java 的类加载机制 Ø学会使用 ClassLoader 进行类加载 Ø理解反射的机制 Ø掌握 Constructor.Method.Field 类的用法 Ø理解并掌握动态代理 1.Class类 –对象照镜子后可以得到的信息:某个类的数据成员名.方法和构造器.某个类到底实现了哪些接口. 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象. 一个 Class 对象包含了特定某个类的有关信息. –  Class 对象只能由系统建立对象.

java基础篇IO流的规律

前两篇降了IO流中的字节流和字符流复制的例子,今天来总结一下IO流的规律 掌握好IO流的规律,再开发中会很好用 下面来总结一下: 1,明确源和目的 源:输入流 InputStream 和Reader 目的:输出流 OutputStream 和Writer 2,操作的数据是否是纯文本. 是:使用字符流 不是:使用字节流 3,当体系明确后,在明确要使用哪个具体的对象,通过设备来进行区分 源设备: 内存,硬盘,键盘 目的设备: 内存,硬盘,控制台 这里的源就是你想进行的操作,比如说你想从c盘复制一个文

黑马程序员——Java基础篇之对象归要

1.static关键字 1.1.static可以修饰成员变量,成员方法,还有类(其中这里的类是内部类) 1.2.static修饰的部分会随着类的加载而加载: 加载过程:当JVM执行static修饰的代码时,会在内存的共享区给static部分开辟一个空间,供该类持有,static部分不是某个对象的部分,而是该类共有的,所以当一个函数会被多个对象调用时,最好定义成static,这样比较节省空间. 1.3.静态方法只能访问静态成员 原因:如果静态方法中调用了非静态的变量,那么由于静态方法是随着类的加载