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();
}
}