ThreadLocal
关于线程范围内的变量共享的举例:监狱里罪犯的排队打饭,针对A罪犯,那几个打饭和打菜和打汤的模块操作的饭盆是A罪犯相关的饭盆;针对B罪犯,那几个打饭和打菜和打汤的模块操作的饭盆是B罪犯相关的饭盆。
首先用如下代码来说明如何实现全局共享:
Class GlobalData
{
public static ThreadLocal var = new ThreadLocal();
}
全局静态变量可以被多个模块类共享,并且不管是哪个线程来调用,数据都是同一份。
接着用如下代码来说全局共享的变量被不同线程调用时,希望有不同的返回值的情况。
Class A{
public void say(){
GlobalData.var.get()
}
}
线程1、线程2 、线程3访问的GlobalData.var得到的对象是否是同一个?要反复强调这是同一个对象。但是,使用的GlobalData.var.get()得到数据是肯定同一个吗?那就不一定了!例如这里要讲的Threadlocal就可以为三个线程分别返回三个不同的值。
三个线程用如下代码来set这个GlobalData.var对象的值时
GlobalData.var.set(new Random().nextInt(10000));
最终存进去了几个值?这时候要为每个线程各自分别存储进去一个值,即总共存储进了三个值。
------------------------------
通过ThreadLocal类的示意代码进行原理分析:
ThreadLocal
{
HashMap hashMap = new HashMap();
void set(Object obj)
{
hashMap.put(Thread.currentThread(),obj);
}
object get()
{
return hashMap.get(Thread.currentThread());
}
}
java5中线程并发库 java.util.concurrent
Volatile的意思是说:在jvm中,一个线程更新了共享变量i,另外一个线程立即去读取共享区中的i时,读到的可能不是刚才另外那个线程更新过的结果,这就类似数据库中的事务隔离级别中的read uncommited,volatile就是解决这个问题的。
关于线程池的讲解:
在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,这就是封装。记住,任务是提交给整个线程池
,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
步骤1:用3个大小的固定线程池去执行10个内部循环10次就结束的任务,为了观察固定线程池下的其他任务一直再等待,希望打印出正在执行的线程名、任务序号和任务内部的循环次数,刚开始看到只有3个线程在执行,并看到任务前仆后继的效果。注意:这10个任务要用各自独立的runnable对象,才能看到任务的序号。
步骤2:改为缓存线程池,可以看到当前有多少个任务,就会分配多少个线程为之服务。
package cn.itcast.foundationsummary;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args) {
//ExecutorService service = Executors.newFixedThreadPool(3);
ExecutorService service = Executors.newCachedThreadPool();
for(int i=1;i<=10;i++){
final int sequence = i;
//仔细品味runnable对象放到循环里面和外面的区别,为了让每个对象有自己独立的编号
service.execute(new Runnable(){
public void run() {
try{Thread.sleep(200);}catch(Exception e){}
for(int j=1;j<=5;j++){
System.out.println(Thread.currentThread().getName() + "is serving "
+ sequence + " task:" + "loop of " + j);
}
}
});
}
/*
用下面这句代码来说明上面的代码是在提交任务,并且所有的任务都已经提交了,但任务是什么时候执行的,则是由线程池调度的!
*/
System.out.println(“all task have committed!”);
//注意与service.shutdownNow()的区别。
service.shutdown();
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1);//定时器
scheduledService.scheduleAtFixedRate(
new Runnable(){
public void run() {
System.out.println("bomb!!!");
}},
5,
1,
TimeUnit.SECONDS);
}
}
启动定时器方式:
1. submit()
2. execute();
3.schedule();
取得绝对值,比如定义在今年年底发生的事件
date.getTime() - System.currentTimeMills();// 用想要的时间减去当前系统时间来定义需要延迟的时间
shutdown与shutdownNow的比较
shutdown 如果仍在为别的程序服务,则需要等待服务完成后停止
shutdownNow 无论线程是否为别的程序服务,立刻停止线程
Callable and Future
提交任务的时候有返回值,而且需要拿到该返回值:
eg:
package cn.itcast.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
//提交一个任务,有返回值
ExecutorService service = Executors.newSingleThreadExecutor();
Future<String> future = service.submit(new Callable<String>(){
@Override
public String call() throws Exception {
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
return "www.itcast.cn";
}
});
System.out.println("task has been committed");
System.out.println(future.get());
//提交多个任务
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(service);
for(int i = 0 ;i <10;i++ ){
final Integer sequence = i+1;
completionService.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
try{Thread.sleep((long) (Math.random()*1000));//随机数让每次任务执行间隔时间不同
}catch(Exception e){
e.printStackTrace();
}
return sequence;
}
});
}
for(int i =0 ;i<10;i++){
Future<Integer> f = completionService.take();
System.out.println(f.get());
}
}
}