java多线程实验⼼得体会_JAVA多线程学习⼼得(⼀)需要的朋友可以看看,代码如有错误,请多提出指正意见。
下⾯说⼀下最近的⼀些⼼得。
Thread和Runnable两种实现⽅式。
这两种⽅法都是最基础的实现线程的⽅法,声明线程对象后,通过调⽤对象的start()⽅法,来执⾏线程内部的run()⽅法。
其中Runnable是由Thread实现的,因此在执⾏Runnable的任务时,⼀般将这个对象作为Thread的⼀个tag来使⽤。
使⽤Thread进⾏实现多线程:
使⽤Runnable进⾏实现多线程:
进⾏⼀个⽣产者消费者模型的构建:
花体英文⽣产者消费者模型是⼀个较为经典的多线程应⽤场景,在该场景中,引⽤到了(wait/notify)等待/通知机制
等待/通知机制:
whore什么意思wait/notify是对象的⽅法,⽽不是线程的。体现在资源上,同⼀时刻,对象的资源只能被同⼀个线程使⽤,线程运⾏完毕后,需要释放资源,并进⼊wait状态,对象再启动notify⽅法,唤醒其他线程运⾏,之后这个线程再次wait,⼀直循环到线程运⾏结束。
liudmila举个例⼦:有⼀群⼈在⼀扇门外等着,每个⼈都想进到门⾥去,但同时最多只能进去⼀个⼈,在这个例⼦⾥,门就是对象,⼈们就是线程;⼀个⼈进门去,相当于占⽤对象资源,其他⼈在门外等着(wait),当这个⼈从屋⾥出来,门开着(notify),就⼜有⼈可以进去,⽽门外的⼈再次进⼊wait状态,⼀直循环到事情结束。
这⾥提⼀下notify,和notifyAll,⼀个是门开着然后只有⼀个⼈看到了,另⼀个是所有⼈都看到了门开着。
也就是说notify只会随机唤醒⼀个等待(也可以叫做阻塞)线程,⽽notify All唤醒了所有等待线程,前者会导致线程效率不⾼,后者会引起线程线程竞争,这时要做的就是确保线程安全;
季札挂剑翻译
关于线程安全的部分留到下⼀篇⽂章讲
当然还有另⼀种办法,Thread.join,是让线程依次执⾏的⼀个⽅法具体表现为当⼀个线程执⾏完毕,才能执⾏下⼀个线程。
/***写⼀个⽣产者消费者模型* (发⽣了死锁,情况如下):* 1x已⽆产品可消费,等待⽣产* 4x已⽆产品可消费,等待⽣产* 2x已⽆产品可消费,等待⽣产* 3x已⽆产品可消费,等待⽣产**/public classDemo3 implementsRunnable{
privateString name;privateList list= newArrayList();private final intsize= 10;public voidproduce(intnum) throwsException {
while(true) {
synchronized(list) {
while(list.size() + num > size) {
holy cow
System.out.println(Thread.currentThread().getName()+"⽣产过剩,等待消费");list.wait();}
System.out.println(Thread.currentThread().getName()+"正在⽣产");for(inti = 0;i < num;i++) {
list.add("hello, world");}
Thread.sleep(1000);}
}
public voidconsume() throwsException {
while(true) {
synchronized(list) {
while(list.size() == 0) {
System.out.println(Thread.currentThread().getName()+"已⽆产品可消费,等待⽣产");list.wait();}
System.out.println(Thread.currentThread().getName()+"正在消费");ve(0);ifyAll();}
Thread.sleep(1000);}
守护甜心36>送友人 李白
}
public voidtName(String name) {
this.name= name;}
public voidrun() {
try{
while("producer".equals(name)){
produce(1);}
while("consumer".equals(name)){
consume();}
}
catch(Exception e) {
e.printStackTrace();}
}
public static voidmain(String[] args) {
try{
Demo3 myThread = newDemo3();myThread.tName("producer");Thread t1 = newThread(myThread,"1x");Thread t4 = newThread(myThread,"4x");t1.start();t4.start();Thread.sleep(1);myThread.tName("consumer");Thread t2 =
newThread(myThread,"2x");Thread t3 = newThread(myThread,"3x");t2.start();t3.start();}
catch(Exception e) {
}
}
}
线程框架Executor,以及对Callable的使⽤:
这个框架主要是可以创建⼀个线程池,也不需要写原⽣的线程对象来进⾏操作,⽐较⽅便。
使⽤⽅式见代码注释/*** 写⼀个Executor 多线程框架**/public classDemo4{
/*** Executor包括四种创建线程池的对象* Java通过Executors提供四种线程池,分别为:* newCachedThreadPool创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。* newFixedThreadPool 创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。* newScheduledThreadPool 创建⼀个定长线程池,⽀持定时及周期性任务执⾏。* newSingleThreadExecutor 创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执⾏。*/public static voidmain(String[] args) throwsExecutionException,InterruptedException {
//创建⼀个定长的线程池 例⼦是10个线程的ExecutorService executorService = wFixedThreadPool(10);//1·框架执⾏execute⽅法,来执⾏⼀个线程类,但是没有返回值//ute(new Demo2.Runner1());//2·使⽤submit执⾏线程,可以得到返回值//Future submit = executorService.submit(new
和莎莫的500天电影
Call1());//System.out.());//3·CompletionService 可以将已完成任务与未完成的任务分离出来ExecutorCompletionService此类将安排那些完成时提交的任务,把它们放置在可使⽤ take 访问的队列上CompletionService completionService = newExecutorCompletionService(executorService);completionService.submit(newCall1());Future future =completionService.take();System.out.());//4·submit⼀个runnable和⼀个callable的区别//主要是靠futureTask 区别,具体在下⾯//可以使⽤lambda表达式进⾏代码优化}
理智是什么意思static classCall1 implementsCallable {
publicString call() {
return"返回callable线程";}
}
static classRun1 implementsRunnable {
public voidrun() {
//return "返回callable线程";}
}
}
FutureTask的使⽤
它实现了Runnable和Future,可以⽤来执⾏Runnable和Callable,都能获得返回值:
Callable当然能返回,这⾥说⼀下void泛型的Runnable,具体返回⽅法,我把源码放出来:
上⾯是Callable下⾯是Runnable,⽽result是作为参数输⼊的,这⾥我们看到调⽤了Executors.callable(runnable,result)
于是明⽩了,Runnable返回值被执⾏并有返回值是因为,返回值是⼀个预期结果,我们去执⾏这个线程并输⼊预期结果,执⾏成功后,这个result会被返回回来。personal interest
FutureTask还适⽤于执⾏多任务计算的使⽤场景,在⾼并发环境下确保任务只执⾏⼀次,以及通过cancel⽅法来取消掉线程等功能。