2:Thread thread = new Thread(objfunctionName); threadstart();
这样自定义的线程是真正的多线程,它的使用也是最灵活的。不像Timer线程,精确度只有50ms。值得注意的是:如果需要启动的线程函数是带输入参数的,怎么办?
有两个办法:
A:你不是启动obj对象里的函数吗?在threadstart();之前,你先添加这句话 MyObject obj = new MyObject(int a ,int b); 这样,objfunctionName函数里可以直接使用a和b了。还有个方法,就是利用委托封装函数,然后threadstart(参数);具体代码如下:
[ComVisibleAttribute(false)]
public delegate void ParameterizedThreadStart(Object obj)
//这个Thread类的构造方法的定义如下:
public Thread(ParameterizedThreadStart start);
public static void myStaticParamThreadMethod(Object obj)
{
ConsoleWriteLine(obj);
}
static void Main(string[] args)
{
Thread thread = new Thread(myStaticParamThreadMethod);
threadStart("通过委托的参数传值");
}
3:利用threadpool线程池技术。threadpool的主要原理是池里面的线程不会完成一个任务就消亡,而是会继续执行其他的任务,这减少了线程的消亡和生成的代价。
主要是ThreadPoolQueueUserWorkItem()和ThreadPoolRegisterWaitForSingleObject(···)两个静态函数。具体如下:
QueueUserWorkItem的使用:
static void ThreadProc(Object stateInfo)
{
ConsoleWriteLine("Hello from the thread pool");
}
Main函数里ThreadPoolQueueUserWorkItem(new WaitCallback(ThreadProc)); 即可。(注意WaitCallback系统委托),它的功能就像第2种方法里提到的new thread。
那么RegisterWaitForSingleObject是干什么的呢?这个方法的做用是向线程池添加一个可以定时执行的方法。有点像第一种方法里提到的timer线程,却不属于UI线程。
具体的使用如下:
AutoResetEvent wait = new AutoResetEvent(false);
object state = new object();
ThreadPoolRegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 5000, false);
//5000是间隔调用的时间,也就是wait变量卡住的timeout时间(我觉得内部是这样实现的)
waitSet(); //如果有set这句话,那么第一次执行不用等5秒,则直接执行目标函数,否则没这句话,第一次执行要等5秒的。
还有一个要注意:我平常使用的是ManualResetEvent,但在threadpool里,首先要选的是AutoResetEvent,因为AutoResetEvent能自动reset,所以下一次间隔来了,又要重新等待5秒钟,达到定时器的目的。如果是ManualResetEvent,要么一次执行不了(初始值为false),要么不间断的玩命执行。
ManualResetEvent和AutoResetEvent的另一个重要区别是前者能一次唤醒多个线程,而后者一次只能唤醒一个线程。
其实RegisterWaitForSingleObject函数的使用有点想我封装好的MyTimer类的实现了:我里面的while死循环里用了个waitwaitone(2000,false);即可。
对了,说到这里,RegisterWaitForSingleObject函数实现的定时器,如果手动停止呢?
这要用到Unregister函数:
RegisteredWaitHandle rw = ThreadPoolRegisterWaitForSingleObject(wait, new WaitOrTimerCallback(test), state, 3000, false);
rwUnregister(wait);
嗯讨论了这么多线程的东西,干脆再说一个小点:ThreadIsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出1、使用pthread库执行多线程,这个是Linux下的线程库 Windows下应该有自己的API,不过这种东西一般还是以Linux为标准。pthread_create()创建一个线程,传入fun()的函数指针就行了。
2、例程:
#include <pthreadh>
#include <stdioh>
#include <sys/timeh>
#include <stringh>
#define MAX 10
pthread_t thread[2];
pthread_mutex_t mut;
int number=0, i;
void thread1()
{
printf ("thread1 : I'm thread 1\n");
for (i = 0; i < MAX; i++)
{
printf("thread1 : number = %d\n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(2);
}
printf("thread1 :主函数在等我完成任务吗?\n");
pthread_exit(NULL);
}
void thread2()
{
printf("thread2 : I'm thread 2\n");
for (i = 0; i < MAX; i++)
{
printf("thread2 : number = %d\n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(3);
}
printf("thread2 :主函数在等我完成任务吗?\n");
pthread_exit(NULL);
}
void thread_create(void)
{
int temp;
memset(&thread, 0, sizeof(thread)); //comment1
/创建线程/
if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment2
printf("线程1创建失败!\n");
else
printf("线程1被创建\n");
if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
printf("线程2创建失败");
else
printf("线程2被创建\n");
}
void thread_wait(void)
{
/等待线程结束/
if(thread[0] !=0) { //comment4
pthread_join(thread[0],NULL);
printf("线程1已经结束\n");
}
if(thread[1] !=0) { //comment5
pthread_join(thread[1],NULL);
printf("线程2已经结束\n");
}
}
int main()
{
/用默认属性初始化互斥锁/
pthread_mutex_init(&mut,NULL);
printf("我是主函数哦,我正在创建线程,呵呵\n");
thread_create();
printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n");
thread_wait();
return 0;
}1、 认识Thread和Runnable
Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口。Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承,况且Runnable只有一个run方法,很适合继承。在使用Thread的时候只需继承Thread,并且new一个实例出来,调用start()方法即可以启动一个线程。
Thread Test = new Thread();
Teststart();
在使用Runnable的时候需要先new一个实现Runnable的实例,之后启动Thread即可。
Test impelements Runnable;
Test t = new Test();
Thread test = new Thread(t);
teststart();
总结:Thread和Runnable是实现java多线程的2种方式,runable是接口,thread是类,建议使用runable实现java多线程,不管如何,最终都需要通过threadstart()来使线程处于可运行状态。
2、 认识Thread的start和run
1) start:
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到spu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
2) run:
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
3、 线程状态说明
线程状态从大的方面来说,可归结为:初始状态、可运行状态、不可运行状态和消亡状态,具体可细分为上图所示7个状态,说明如下:
1) 线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但不管怎样,当我们new了thread实例后,线程就进入了初始状态;
2) 当该对象调用了start()方法,就进入可运行状态;
3) 进入可运行状态后,当该对象被 *** 作系统选中,获得CPU时间片就会进入运行状态;
4) 进入运行状态后case就比较多,大致有如下情形:
·run()方法或main()方法结束后,线程就进入终止状态;
·当线程调用了自身的sleep()方法或其他线程的join()方法,就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源)。当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配时间片;
·当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被锁牢(synchroniza,lock),将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入可运行状态,等待OS分配CPU时间片;
·当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。
·当线程调用stop方法,即可使线程进入消亡状态,但是由于stop方法是不安全的,不鼓励使用,大家可以通过run方法里的条件变通实现线程的stop。
1、继承Thread类实现多线程:
代码如下图。在Demo类中继承Thread类并覆写了run方法,在主方法中调用Demo对象d1,d2实现了两个线程同时运行的目的
2、实现Runnable接口实现多线程:
代码如下图。同样是Demo类我们实现了Runnable接口,同样覆写了run方法,在主方法中利用Demo类的对象来新建Thread类的对象从而实现两个线程同时运行的目的。
有时候感觉自己是个效率很高的人,有时候又觉得其实什么都没有做,那些在做的事情似乎都可以放下不管,无所事事,等deadline来的时候,一下子就都慌乱起来,结果就会越来越陷入这个循环里。线程1:
家庭系列类网课,
每周1-2次集中线上学习,1-2次线上练习,线下1-2次复习,看书5本以上。
线程2:
导师班学习,
隔周1次线下学习,看书,每周1-2次复盘学习
线程3:
每周2次三级修学学习,
每天2小时左右自学、每周1-2次准备分享内容
线程4:
每周一次婚姻家庭咨询师志愿者服务
隔月督导,隔月讲座
准备督导材料、讲座材料
线程5:
每月讲师志愿者活动,
准备讲稿内容、素材,组织讲座
线程6:
Daily:复习备考社工考试
线程7:
Daily:复习备考lies
线程8:
热线小组
drm组长工作、每周一次线上热线、线上/线下隔周朋辈督导
hd每周一次线下热线+现场督导
线程9:
自己带的团体——
读书会:每周一次线上分享、每周排班
助人小组:每周一次地面学习
oh卡:最近组织暑期系列地面活动
线程10:
每周3-4次,对外汉语教学
线程11:
哲学读书会
已经掉了无数的课…
线程12:
督导学习
hd每月两次线下团体督导
zxzj每天线上督导或公开学习观摩课
线程13:
xs:短视频拍摄
目前项目进度0
线程14/15/…
计划中的需要学习的系列课程——
9月开始一年的沙盘;
8月开始1年的叙事;
……
不要理我——已碎,低头捡ing。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)