CopyWrite容器机制
适用于读多写少的的情况
注意:CopyWrite 只能保证数据最终一致性,不能保证数据的实时一致性, 如果希望写入的数据马上能读到。请不要使用CopuOnWrite
(Queue)队列:用于保存一组元素,不过在存取的时候遵循先进先出原则。
(Deque)双端队列:两端都可以进出队列
(BlockingQueue) 支持两个附加操作的队列,在队列为空时,获取元素的线程会等待队列变为非空,在队列满了的时候,存储元素的线程会等待队列可用
适用场景:生产,消费者情况
并行:1个进程中的多个线程同时运行
并发:多个进程同时运行
优先级线程队列:PriorityBlockingQueue
CountDownLatch(线程计步器)
应用场景1:开启五个线程去下载,当5个线程都执行完了才算下载成功
应用场景2:当用户多文件上传的时候,可以采用多线程上传,当多个文件都上传成功的时候才算真正的上传成功
public class CountDownLatchTest {
public static void main(String[] args) {
try{
CountDownLatch latch=new CountDownLatch(3);
Worker worker1=new Worker("1", latch);
Worker worker2=new Worker("2", latch);
Worker worker3=new Worker("3", latch);
worker1.start();
worker2.start();
worker3.start();
latch.await();
System.out.print("main thread end!");
}catch(Exception e){
System.out.print(e.getMessage());
}
}
}
import java.util.concurrent.CountDownLatch;
public class Worker extends Thread {
private String workName;
private CountDownLatch latch;
public Worker(String workerName,CountDownLatch latch){
this.workName=workerName;
this.latch=latch;
}
@Override
public void run() {
try{
System.out.println("Worker:"+workName+"is begiin");
Thread.sleep(1000L);
System.out.println("Worker:"+workName+"is end");
System.out.println("Worker:"+workName+System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}
latch.countDown();
}
}
其中这5个线程是同时并发执行的。
线程池:
Executors:线程池的工具类
newSingleThreadExcutor:
newCachedThreadPool();
newSingleThreadExecutor();
newFixedThreadPool();
合理利用线程池:
1.降低线程创建和销毁造成的消耗
2.提高相应速度
3.提高线程的可管理性
4.防止服务器过载
核心队列:
线程等待池
任务处理池
核心池大小
最大处理线程池数
fork/join 框架:
fork():这个方法决定了ForkJoinTask的异步执行,这个方法可以创建新任务
join(),负责在计算完成后返回记过。因此允许一个任务等待另一个任务执行完成
private static final long serialVersionUID=3336021432713606929L;
private static int spliteSize=2;
private int start,end;
public CountTask(int start,int end) {
this.start=start;
this.end=end;
}
@Override
protected Integer compute() {
int sum=0;
boolean canCompute=(end -start)<spliteSize;
if(canCompute){
for(int i=start; i<=end; i++){
sum=sum+i;}
}else{
int middle=(start +end)/2;
CountTask firstTask=new CountTask(start, middle);
CountTask secondTask=new CountTask(middle+1, end);
firstTask.fork();//开始执行
secondTask.fork();
int firstResult=firstTask.join();
int secondResult=secondTask.join();
sum =firstResult+secondResult;
}
return sum;
}
}
public class ForkJoinTaskDemo {
public static void main(String[] args) {
try{
ForkJoinPool forkJoinPool=new ForkJoinPool();
CountTask task=new CountTask(1, 5);
Future<Integer> result=forkJoinPool.submit(task);
System.out.println("结果"+result.get()+"---"+System.currentTimeMillis());
CountTask task2=new CountTask(1, 100);
Future<Integer> result2=forkJoinPool.submit(task2);
System.out.println("--100结果 "+result2.get()+"---"+System.currentTimeMillis());
System.out.println("Thread Main End");
}catch(Exception e){
e.printStackTrace();
System.out.println("error");
}
}
}
final 修饰全局变量时,要在变量定义的时候赋值,或者在构造器中赋值
当final 修饰的变量是 基本数据类型和 Sting时,相当于直接访问常量
final修饰类时,这个类不能被其他类继承。
修饰方法:1.锁定方法,不能被其他类所继承
线程池监控:
自定义线程池继承ThreadPoolExecutor 并且实现
//线程开始执行的时候 执行。
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("Work_task beforeExecute thread is:" +t.getName());
}
//执行完某个线程之后 执行这个方法
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
System.out.println("Work_task after worker thread is:" +r);
}
//所有线程全部执行完毕的时候执行
@Override
protected void terminated() {
// super.terminated();
}
java 内存管理机制
在高并发模式下,会浪费内存,GC 回收执行时间太频繁。
内存图:
JVM 程序计数器
一块较小的内存空间(线程私有的内存),作用可以看成 当前线程所执行的字节码的行号指示器
每条线程都需要独立的程序计数器
JVM栈
java虚拟机栈(为虚拟机调用程序方法服务),线程私有。虚拟机栈分为局部变量表,操作数栈,动态链接,方法出口。虚拟机栈的局部变量表存放了 编译器可知的8中基本类型数据。对象的引用(不是实例本身)
本地方法栈
为虚拟机调用的操作系统本地方法服务
共享堆
堆被所有线程共享,存放对象实例。垃圾收集器管理的主要区域
方法区(非-堆空间)
被各个线程共享的内存区域,存储已被虚拟机加载的类信息,常量,静态变量。即时编译后的代码等数据。java虚拟机把方法区归为堆的一部分。
JVM回收机制把JVM中的堆和非堆区分为三代
年轻代:(Eden(伊甸园), survior(幸存者),survior)动态的存储,存储生命周期短的对象,新产生的对象。Eden 满了之后 会调用
MinorGC 把内存对象拷贝到Survivor
年老代:存储生命周期长的对象
永久代:年老代的移过来的对象
MinorGC:年轻代所进行的垃圾回收
MajorGC:老年代进行的垃圾回收,MinorGC速度比MinorGC慢上10倍
FullGC:整个堆内存进行的垃圾回收
JVM垃圾回收过程中内存分配原则。
- 对象优先分配在Eden区,Eden没有足够的空间是,虚拟机执行一次minorGC
2.大对象(指需要大量连续内存空间的对象)直接进入老年代
3.长期存活的对象进入在老年区,每经过一次 MinorGC,那么对象会进入survivor区,每经过一次MinorGC,那么对象年龄加1。当年龄大于阈值时进入年老代
4.Survivor区中相同年龄的所有对象大小总合大于Survivor空间的一半,年龄大于或等于对象可以直接进入老年代
5.每次进行MinorGC时,JVM会计算Survivor区移到老年区对象的平均大小。如果这个值大于老年区的剩余值大小。则进行一次FullGC
JVM在启动的时候会自动设置JVM Heap的值,JVM 提供 -Xmn -Xms -Xmx等选项进行设置
可视化监控工具:
1.VisualVM
2.JConsole:内置java性能分析器
eclipse中有内置调试器 integrated debugger
Badboy,JMeter 强大的测试工具。
MultithreadedTC 测试并发
android 进程的生命周期
1.前台进程:满足以下条件其中之一即可:
a.本进程中有activity与当前的用户有交互
b.本进程中有Service与当前的用户有交互
c.本进程中有在前台运行的Service(Service 调用过startForegroud)
d.本进程中有Service 正在执行 某个生命周期回调函数
2 可见进程
a.部分可见的activity
b.含有绑定到可见activity的service
3.服务进程
进程运行了某个使用startService()启动的Service 后台播放音乐 网络下载文件
4.后台进程activity的stop()已经被调用 可以随时被杀死 LRU算法
5.空进程:进程 不运行任何活动的应用程序组件。 因为缓存而保持
Hashtable用的是方法锁
java.util.concurrent下的类使用的是代码块锁,用了锁分离技术