目录
昨日总结
了解Vector (同步锁),了解缓存(未完结),实现黑马点评短信登录、商铺缓存与数据库的双写一致
- 找文献
- 背诵小林coding--Java并发面试篇(1/6)
- 代码随想录——环形链表|| 、 有效的字母异位词
今日计划
- 继续了解缓存问题,跟进点评项目
- 找文献,复现代码
- 背诵小林coding--Java并发面试篇(1/3)
- 代码随想录——两个数组的交集,两数之和
算法
循环链表
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 :
输入:head = [3,2,0,-4], pos = 1输出:返回索引为 1 的链表节点解释:链表中有一个环,其尾部连接到第二个节点。
有点偏向数学找规律
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while(true) {
if(fast == null || fast.next == null)
return null;
fast = fast.next.next;
slow = slow.next;
if(fast == slow)
break;
}
fast = head;
while(slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的 字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"输出: true
示例 2:
输入: s = "rat", t = "car"输出: false
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length() != t.length())
return false;
int [] co = new int[26];
for(char c : s.toCharArray()) {
co[c - 'a']++;
}
for(char c : t.toCharArray()) {
co[c - 'a']--;
if(co[c - 'a'] < 0) {
return false;
}
}
return true;
}
}
缓存
缓存的作用
缓存的成本


缓存更新策略
- 内存淘汰
- 超时剔除
- 主动更新
- 对于缓存的操作,应更新数据库时让缓存失效,查询时再更新缓存。而不是每次更新数据库都更新缓存,这样效率太低
- 要保证缓存与数据库的操作同时发生,采用事务的方式
- 对于数据库与缓存谁先操作的问题,应先操作数据库在删除缓存。因为在查询缓存未命中后,他需要查询数据库;这是如果另一个线程来操作数据库,更新的操作要比查询数据库的操作提前的情况概率 要小很多。 如果先删除缓存在操作数据库,一旦缓存删除,这是查询的情况很多,查询的速度一定是快于更新数据库的。所以这种情况下发生数据不一致的概率更高 。

Vector
- 是java中的一个经典的集合类,是一个动态的数组,属于矢量队列,继承与AbstractList,实现了List
- 它是线程安全的,所有的方法都通过synchronized关键字修饰,确保多线程环境下的线程安全。
- Vector的线程安全机制简单,无须手动同步,在多线程环境下无须额外加锁。但是每次方法调用都需要获取锁,高并发下性能较低,同时也会阻塞其他进程,在现代Java开发中,推荐使用更高效的线程安全集合(CopyOnWriteArrayList等)。
- 对于扩容机制,默认初始容量为10, 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加 容量增加系数;否则,将容量大小增加一倍。
同步锁
是用来解决多线程安全问题的(也叫高并发,当多个线程同时修改一个资源时,就会出现线程安全的问题)
同步锁是一种阻塞式的锁机制。当一个线程获取到同步锁后,其他试图获取该锁的线程会被阻塞,直到持有锁的线程释放锁。
package com.hmdp;
public class Demo {
static Integer num=10;
public static void main(String[] args) {
final DemoSyn syn=new DemoSyn();
Thread t1=new Thread(){
public void run(){
syn.printNum(0);
}
};
Thread t2=new Thread(){
public void run(){
syn.printNum(1);
}
};
t1.start();
t2.start();
}
public void printNum(int i){
//synchronized(this){
if(i==0){
num=100;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
num=200;
}
System.out.println(num);
// }
}
}
当注释掉synchronized(this){}时,输出的结果会是100,100或者 200,200.因为没有用到同步锁对两个线程进程进行加锁处理
昨日八股联想答案
-
Java里的多线程和操作系统里的多线程一样吗,要注意哪些问题
Java里的多线程是基于操作系统的多线程机制实现的,二者本质上都是为了提高系统的并发处理能力和资源利用能力。当Java程序创建一个新线程时,JVM会请求操作系统创建一个对应的内核线程,由操作系统负责该内核线程的调度、上下文切换等操作。
要注意线程安全问题,保证数据的一致性
- 线程的创建方式
- 直接继承Thread类,在该类中重写run方法(线程执行的代码),之后在主函数中创建线程对象,来调用start()方法启动线程。
- 实现Runnable接口,如果当一个类继承了其他的类,就不可以在直接继承Thread类了。因此可以继承Runnable接口,同上重写run方法,不同的是将此Runnable对象作为参数传递给Thread类的构造器
- 使用线程池
- Java的线程状态有哪些
new(新建状态):线程被创建但尚未启动
RUNNABLE(可运行状态):线程已经调用了start()
方法,线程正在JVM中执行。
BLOCKED(阻塞状态):线程被阻塞
WAITING(等待状态):线程处于无限期等待状态,直到其他线程显式地唤醒它
TIMED_WAITING(计时等待状态):线程处于有限时间的等待状态。
TERMINATED(终止):线程执行完毕
今日八股联想
-
不同的线程之间如何通信?
-
线程间通信方式有哪些?
-
如何停止一个线程?
总结
继续开始学