线程高级以及java内存学习记录

线程学习记录一

CopyWrite容器机制

适用于读多写少的的情况
注意:CopyWrite 只能保证数据最终一致性,不能保证数据的实时一致性, 如果希望写入的数据马上能读到。请不要使用CopuOnWrite

(Queue)队列:用于保存一组元素,不过在存取的时候遵循先进先出原则。
(Deque)双端队列:两端都可以进出队列

QueueUML类图
(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垃圾回收过程中内存分配原则。

  1. 对象优先分配在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下的类使用的是代码块锁,用了锁分离技术

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值