java学习
[toc]
第一章线程安全
1.1 ThreadLocal理解
/**
这是一个ThreadLoca的内部Map
涉及到3个类
Thread
ThreadLocal
ThreadLocal.ThreadLocalMap
关系:
一个Thread对象里面有一个ThreadLocal.ThreadLocalMap,相当于是一个线程就一个ThreadLocalMap对象.
这个ThreadLocalMap里面的key是ThreadLocal对象, value是传递进行来的值
**/
Thread.class里面
ThreadLocal.ThreadLocalMap threadLocals = null;
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
/**
set 操作
**/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/**
get操作
**/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
//通过当前线程,或者ThreadLocal
ThreadLocalMap getMap(Thread t) {
//每一个线程 存一份ThreadLocal.ThreadLocalMap
return t.threadLocals;
}
1.2 CAS
代码块
1.3 AQS
LockSupport
1.先说一下理解。 这个东西是一个许可。 就是 0/1 俩个信号量
2.LockSupport.park() //获取许可
3.LockSupport.unpark(Thread thread) //释放许可
-------------------------------------------------
默认这个许可是被占用的。。
public static void test1(){
//许可默认是被占用的。。。
LockSupport.park();
System.out.println("线程一直处于阻塞状态。。");
}
------------------------------------------------
public static void test2(){
//许可默认是被占用的。。。
Thread thread = Thread.currentThread();
//释放许可
LockSupport.unpark(thread);
//获取许可
LockSupport.park();
System.out.println("1.释放许可, 2,获取许可, 打印");
}
------------------------------------------------
public static void test3(){
//LockSupport是不可重入 一个线程连续俩次 park 也会阻塞
Thread thread = Thread.currentThread();
//许可默认是被占用的。。。
//释放许可
LockSupport.unpark(thread);
//得到许可
LockSupport.park();
System.out.println("可以打印");
//再次获取许可。。失败
LockSupport.park();
System.out.println("不可以打印");
}
ReentrantLock
AQS核心是利用CAS的理论,结合双向队列(lock)和单向队列(Condition)来实现的。
1.4 volatile 线程安全吗?
不安全的。还是存在i++的问题。
1.5 Callable 和 Runnable 区别
/**
Callable 是一个有返回值的的,一般结合Future使用。
**/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
/**
Runnalbe 是一个没有返回值的,正常线程的使用。
**/
@FunctionalInterface
public interface Runnable {
void run();
}
1.6 Future 阻塞, 超时设置
Future.get();//线程阻塞的。
//线程阻塞,等待一段时间,然后抛出异常
Future.get(long time,TimeUtil util);
1.7 ExecutorService 四种
代码块
1.8 停止一个线程
停止一个线程
1.9 多线程之间的通信和协作
1.10 ReentrantLock
详见上面<a href='#1.2 CAS'>ReentrantLock</a>
1.11 SynchronizedMap
1.12 HashMap
1.13 HashTable
1.14 并发框架
CopyOnWriteArrayList
CopyOnWriteArrayList
CountDownLatch
CountDownLatch
1.15 并发容器
CountDownLatch
CountDownLatch
CyclicBarrie
1.16 线程池
Executors
这个是创建的线程池, 也就是相当于创建Thread 肯定里面需要的是Runnable接口来的实线啦。
//1.创建一个线程
ExecutorService es = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
es.submit(()->{
System.out.println(Thread.currentThread().getId());
});
}
//2.创建一个固定大小的线程池
ExecutorService es = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
es.submit(()->{
System.out.println(Thread.currentThread().getId());
});
}
//3.创建一个缓冲池的线程池,根据系统的内存
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
es.submit(()->{
System.out.println(Thread.currentThread().getId());
});
}
//4.创建一个可以调度的线程池,这个特殊,可以延迟执行。。
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 10; i++) {
es.schedule(()->{
log.info("{}",Thread.currentThread().getId());
},new Random().nextInt(10),TimeUnit.SECONDS);
}
ExecutorService
执行线程的方法有俩个
1.void execute(Runnable command);//没有返回值
2.<T> Future<T> submit(Callable<T> task);//有返回值
eg:
ExecutorService executorService = Executors.newSingleThreadExecutor();
//Runnable接口
executorService.execute(()-> {
log.info("this is 没有返回值");
});
//Callable 接口
Future<Integer> future = executorService.submit(()->{
log.info("this is 有返回值");
return 1;
});
Integer result = future.get();
ThreadPoolExecutor
上面的是jdk为了方便定义的一些线程池,但是我们伟大的程序员怎么能不自己创建呢。。这个类就是自己创建线程池的源码。
参数解释:
corePoolSize:池中保留的线程数
maximumPoolSize:池中最大的线程数
keepAliveTime:当线程池中的线程大于corePoolSize时候,等待新任务之前的保留时间
unit:上面的保留时间
workQueue:工作队列,用于保留执行任务之前的任务。 LinkedBlockingQueue
1.直接切换
2.使用无界队列 LinkedBlockingQueue
3.使用有界队列 ArrayBlockingQueue
threadFactory:创建新线程的工厂 DefaultThreadFactory->new Thread()
handler:拒绝策略 :线程池满啦,工作队列满啦。
1.AbortPolicy 直接抛出异常 默认策略
2.CallerRunsPolicy:用调用者所在的线程来执行任务;[没看懂]
3.DiscardOldestPolicy 丢弃阻塞队列最前面任务,并且执行当前任务
4.DiscardPolicy 丢弃任务
Executors.newSingleThreadExecutor(); //里面的实现
new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
1.18 a