1、多个线程访问同一资源时如何保证线程之间访问的顺序性。
a、方案一
1 package com.xiyao.opensource.java.lang; 2 3 public class ThreadT { 4 5 /** 6 * 1、volatile修改,保持signal在多线程之间的可见性 7 * 2、对象监视器就像是一个绳子,使用这个监视器的都是一条绳上的蚂蚱 8 * 3、为了保持一直活动下去,一个蚂蚱休息前一定要唤醒别的至少一个蚂蚱 9 */ 10 volatile static Object signal = new Object(); 11 12 public static void main(String[] args) { 13 Thread thread = new Thread() { 14 @Override 15 public void run() { 16 while(true) { 17 try { 18 Thread.sleep(1000L); 19 /** 20 * 1、notify和wait必须使用在synchronized中 21 * 2、他们都是操作对象监视器,synchronized指明了对象监视器对象 22 */ 23 synchronized(signal) { 24 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 25 signal.notify(); 26 signal.wait(); 27 } 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } 31 } 32 } 33 34 }; 35 thread.start(); 36 while(true) { 37 try { 38 Thread.sleep(1000L); 39 synchronized(signal) { 40 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 41 signal.notify(); 42 signal.wait(); 43 } 44 } catch (InterruptedException e) { 45 e.printStackTrace(); 46 } 47 } 48 } 49 50 }
方案二
1 package com.xiyao.opensource.java.util.concurrent; 2 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurrent.locks.Lock; 5 import java.util.concurrent.locks.ReentrantLock; 6 7 public class LockT { 8 9 public static void main(String[] args) { 10 Lock lock = new ReentrantLock(); 11 //派生出多个条件(每个都是一个信号量) 12 Condition signalOne = lock.newCondition(); 13 Condition signalTwo = lock.newCondition(); 14 Thread thread = new Thread() { 15 @Override 16 public void run() { 17 while(true) { 18 try { 19 //抢占对象监视器 20 lock.lock(); 21 Thread.sleep(1000L); 22 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 23 signalOne.signal(); 24 signalTwo.await(); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 }finally { 28 lock.unlock(); 29 } 30 } 31 } 32 33 }; 34 thread.start(); 35 while(true) { 36 try { 37 lock.lock(); 38 Thread.sleep(1000L); 39 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 40 signalTwo.signal(); 41 signalOne.await(); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 }finally { 45 lock.unlock(); 46 } 47 } 48 } 49 }
方案三
1 package com.xiyao.opensource.java.util.concurrent; 2 3 import java.util.concurrent.SynchronousQueue; 4 5 public class BlockingQueueT { 6 7 /** 8 * 1、这里至少将一种思想,该实现是不严谨的,因为没有两者之间没有监视器 9 * 2、监视器只允许同一时间一个执行 10 * 3、该例子因为try中不是一个完整的方法,所以可能存在一个放入了对象还没打印,对方已经抢先又执行了一次 11 * @param args 12 */ 13 public static void main(String[] args) { 14 /** 15 * LinkedBlockingQueue 16 * ArrayBlockingQueue 17 * PriortyBlockingQueue 18 * SynchronousQueue 19 */ 20 SynchronousQueue queue = new SynchronousQueue(); 21 Thread thread = new Thread() { 22 @Override 23 public void run() { 24 while(true) { 25 try { 26 Thread.sleep(1000L); 27 queue.put(new Object()); 28 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 } 33 } 34 35 }; 36 thread.start(); 37 while(true) { 38 try { 39 Thread.sleep(1000L); 40 queue.take(); 41 System.out.println(Thread.currentThread().getName()+" 我执行完了!"); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 } 45 } 46 } 47 }
2、确定对象是否还活着的方式及优缺点
1、引用计数法:给对象添加一个引用计数器,每当有地方引用它的时候,计数器就加一;当引用失效时,计数器就减一。
a、优点:实现简单,判断效率高
b、缺点:很难解决对象之间相互引用的关系
2、可达性分析算法:从GC Roots对象开始作为起始点,搜索锁走过的路径,当gc roots没有任何引用时则判定其为可回收对象
a、GC root对象:虚拟栈的本地变量表中引用的对象,方法区中类静态属性引用的对象,方法区常量引用的对象,本地方法栈中Native方法引用的对象。
b、要进行GC停顿,GC停顿时分析和垃圾回收一起进行
ps:
a、当对象被认定是可回收时,它会被标记且进行一次筛选(筛选的条件是对象是否有必要执行finalize方法),当没有覆盖finalize或finalize已被调用,则这个对象会被放到一个F-Queue队列中,
之后会进行第二次标记(若对象没在finalize中重新建立引用),未被标记的对象则会被删除
b、枚举根节点(GC Roots):这是可达性分析的需要,Hotspot中使用一组OopMap记录了存放对象引用的地方。
c、安全点:为了减少减少OopMap和引用关系的变化,只在停顿点记录OopMap,线程也是跑到这个点才会执行GC。方法调用、循环跳转、异常跳转
d、安全区:针对阻塞的线程,只有GC万了线程才能离开。
3、垃圾收集的算法及优缺点
1、标记-清楚算法:将需要回收的对象进行标记,然后清除标记处的内存。
a、标记和清除效率都不高
c、会造成内存碎片
2、复制算法:将内存一份为二A和B、将A中活着的对象copy到B中,然后格式化A
a、内存缩小了一半
b、复制效率低
3、标记-整理算法:与复制算法相比,将所有存活的对象拷贝移动到一边,然后清理边界之外的内存。
a、复制效率低
4、分代收集算法:内存进行精确划分,年轻代(eden,survivor*2)、老年代、永久代
1、年轻代用复制算法,minor gc
2、老年代、永久代用标记-清除、标记-整理算法
4、不同版本jdk的变化
参见:https://blog.csdn.net/pursue_vip/article/details/78692584
5、不同垃圾收集器的特点及优缺点
6、内存的分配及回收策略
8、内存分配与回收策略
1、主要分配在新生代eden取上,如果启动本地线程分配缓存,这按线程有限在TLAB(线程本地分配缓存区)上分配
2、有些对象可以直接分配老年代
a、大对象(survivor无法容纳也可以参数设置)
b、到达指定年龄(15)
c、动态年龄判定(survivor中所有对象大小总和大于其空间一般,年龄大于或等于该年龄的对象都会进入老年代)
d、空间担保(老年代最大连续空间小于survivor晋升对象的平均值就要Full GC)
参见:https://blog.csdn.net/xiaomingdetianxia/article/details/77688945
9、解决高并发秒杀商品的思路
10、慢查询
11、抢红包的思路
12、ArrayList的实现逻辑