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();
- }
- }
欢迎大家评论,,大家能够讨论讨论咱们所学的知识点有些什么实际应用场景!!!这也是我们最终学习新知识的最终目的!!!