Shawn 原创,转载请注明!
原文地址:http://blog.csdn.net/a15874647/article/details/6440998
ThreadLocal的使用,,,实际上相当于维护了一个Map,其中以键值对的形式,存储了某一个数据被多个线程访问所对应的值。当然这个数据只能有一份,可以是List。。可以是对象。。可以是javabean。。。其Map中每一个Entry保存进去的键就是当前线程,值就是这个线程所访问的那份数据。。。。比方说在服务器端单独起一个独立线程来实现与某个客户端交互,,,其中交互过程里所有涉及到的公共模块所访问的都是一份数据,,所以顾名思义被叫做线程范围内的数据共享。。。。。想象的到在javaEE中的应用是非常多的。。。。
package localTest; //import java.util.HashMap; //import java.util.Map; import java.util.Random; public class ThreadLocalTest { public static int data; // public static Map dataMap = new HashMap(); // public static ThreadLocal dataLocal = new ThreadLocal(); public static void main(String[] args) { for (int i = 0; i < 2; i++) { new Thread() { public void run() { // ThreadLocalTest.data = new Random().nextInt(); // ThreadLocalTest.dataMap.put(Thread.currentThread().getName(), // new Random().nextInt()); // ThreadLocalTest.dataLocal.set(new Random().nextInt()); int data = new Random().nextInt(); MyData.getInstance().setData(data); System.out.println(Thread.currentThread().getName() + " put data : " + data); System.out.println(Thread.currentThread().getName() +" A get data : " + new A().get()); System.out.println(Thread.currentThread().getName() +" B get data : " + new B().get()); } }.start(); } } } class A { public int get() { // return (Integer)ThreadLocalTest.dataLocal.get(); return MyData.getInstance().getData(); } } class B { public int get() { // return (Integer)ThreadLocalTest.dataLocal.get(); return MyData.getInstance().getData(); } } class MyData{ private static ThreadLocal<MyData> myData = new ThreadLocal<MyData>(); private int data; public int getData(){ return data; } public void setData(int data){ this.data = data; } private MyData(){} public static MyData getInstance(){ MyData data = myData.get(); if(data==null){ data = new MyData(); myData.set(data); } return data; } }
接着是线程并发库中的java.util.concurrent.atomic包中提供了对一些数据类型的扩展,使得对那些数据类型的操作封装成为了方法,而那些方法都是线程安全的,atomic解释是原子的,,支持在单个变量上解除锁的线程安全编程。。。。其中包括Integer,boolean以及IntegerArray和引用类型。。
接下来就是线程池了,,于jdbc数据库连接池同理,,大大的提高了程序运行的效率。。因为创建一个新的线程还是很耗资源的。。
我们也只需要用到一个类,,java.util.concurrent包的老大,,,Executors类,,提供一系列静态方法,用于创建各种线程池,,其中包含固定大小线程,和自动大小线程池(通过任务数量来分配线程数量),以及单一线程池(始终保持有一个线程在池子里)。。。还有可调度的线程池,相当于定时器。。其中定时器任务代码内还可嵌套另外的定时器。。。通过调用线程池的shutdown方法在任务执行完毕后杀死池内线程。shutdownNow直接杀死。。interrupt!ALL!!!
package concurrent; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolTest { public static void main(String[] args) { ExecutorService pool = Executors.newCachedThreadPool();//Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int taskId = i; pool.execute(new Runnable() { public void run() { for (int j = 0; j < 10; j++) { try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " execute task " + taskId + " loop for " + j); } } }); } pool.shutdown(); } } package concurrent; import java.util.Calendar; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TimerTaskTest { private static int count; public static void main(String[] args) { System.out.println(Calendar.getInstance().get(Calendar.SECOND)); final ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); class MyTask implements Runnable{ public void run(){ count++; System.out.println(Calendar.getInstance().get(Calendar.SECOND)); System.out.println("bombing!"); if(count%2==1) timer.schedule(new MyTask(), 4, TimeUnit.SECONDS); else timer.schedule(new MyTask(), 3, TimeUnit.SECONDS); } } timer.schedule(new MyTask(), 2, TimeUnit.SECONDS); } }
Callable让线程能够拥有返回值,类似于Runnable接口,,需要实现call方法,,Future类接受一个Callable的返回值。。。通过get方法获取返回值,当没有数据时,它将会等待,什么时候有数据什么时候获取,通过get方法的重载方法可以设置等待时间。。多个Callable利用CompletionService对象来接收返回值,通过submit来接受提交的任务!!!接受返回值时谁先有数据就提取谁的数据!通过take方法放回一个Future对象再调用get方法获取数据。
package concurrent; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class CallableTest { public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newSingleThreadExecutor(); Future<String> future = pool.submit(new Callable<String>() { @Override public String call() throws Exception { // TODO Auto-generated method stub Thread.sleep(3000); return "Hello world!"; } }); try { System.out.println(future.get(4,TimeUnit.SECONDS)); } catch (Exception e) { e.printStackTrace(); } pool.shutdown(); submit(); } public static void submit() throws Exception{ Executor executor = Executors.newCachedThreadPool(); CompletionService<Integer> service = new ExecutorCompletionService<Integer>(executor); for(int i=0;i<10;i++){ final int sep = i; service.submit(new Callable<Integer>() { public Integer call() throws Exception { Thread.sleep((int)(Math.random()*1000)); return sep; } }); } for(int i=0;i<10;i++){ System.out.println(service.take().get()); } } }
lock,,,普通锁,,以及读写锁,,可以实现读与写之间互斥,读于读之间可以并行,写于写之间也互斥!!
面试题一道,,通过读写锁编写一个缓存类得实际应用
package concurrent; import java.util.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class CacheClass { public static void main(String[] args) { //test(); } private ReadWriteLock rwl = new ReentrantReadWriteLock(); private Map<String,Object> cacheData = new HashMap<String,Object>(); public Object get(String key){ rwl.readLock().lock(); Object obj = null; try { obj = cacheData.get(key); if(obj==null){ rwl.readLock().unlock(); rwl.writeLock().lock(); obj = "Shawn";//readDatabase(); cacheData.put(key, obj); rwl.writeLock().unlock(); rwl.readLock().lock(); } } finally { rwl.readLock().unlock(); } return obj; } }
以及通过面向对象设计的一另一道面试题,,子线程执行5次,主线程执行10次,这样循环总共10次。。。通过synchronized关键字修饰子线程和主线程需要执行的方法封装到一个类当中,通过一个boolean变量来标识子线程和主线程的执行次序。。。然后各自循环10次。。。同样实现两个子线程和一个主线程来交替执行,这个时候就需要用到显示锁,通过多个条件变量(condition)来实现,,线程1获得锁,执行完释放并通知条件变量2,线程2获得锁,执行完释放并通知条件变量3,以此类推,,4个或5个线程交替执行也同理!!!
package concurrent; public class InterViewSubject { public static void main(String[] args) { init(); } private static void init() { final MyData data = new MyData(); new Thread() { public void run() { for (int i = 0; i < 10; i++) { data.sub(); } } }.start(); for (int i = 0; i < 10; i++) { data.main(); } } } class MyData { private boolean isMain; public synchronized void sub() { if (!isMain) { for (int i = 0; i < 5; i++) { System.out.println("sub Thread loop for : " + i); } } else try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } isMain = true; this.notify(); } public synchronized void main() { if (isMain) { for (int i = 0; i < 10; i++) { System.out.println("main Thread loop for : " + i); } } else try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } isMain = false; this.notify(); } }
欢迎大家评论,,大家能够讨论讨论咱们所学的知识点有些什么实际应用场景!!!这也是我们最终学习新知识的最终目的!!!