线程并发 共享数据及线程并发
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());
- }
- }
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;
- publicclass ThreadPoolTest {
- publicstaticvoid main(String[] args) {
- //ExecutorService service = Executors.newFixedThreadPool(3);
- ExecutorService service = Executors.newCachedThreadPool();
- for(int i=1;i<=10;i++){
- finalint sequence = i;
- //仔细品味runnable对象放到循环里面和外面的区别,为了让每个对象有自己独立的编号
- service.execute(new Runnable(){
- publicvoid 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(){
- publicvoid run() {
- System.out.println("bomb!!!");
- }},
- 5,
- 1,
- TimeUnit.SECONDS);
- }
- }
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;
- publicclass CallableAndFuture {
- /**
- * @param args
- */
- publicstaticvoid 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());
- }
- }
- }
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()); } } }