As the saying goes: the shorter the word, the bigger the problem.
Today, Ali’s interviewer asked me to implement a login interface. If the same user fails to log in for 5 times in 10 minutes, it will take 30 minutes to log in.
Of course, the big guy estimates that a see this kind of problem will be very sad, a little algorithm is not interesting. I was fooled as soon as I was a rookie. Login interface? Five times in a row within 10 minutes? Wait 30 minutes to log in?? Login verification ????
“FirstFailTime” is a variable that will record the time of the first login failure. It is a dynamic variable that changes constantly, so a single variable is not easy to implement. If you fail 4 times in the first 10 minutes and again in the 11th minute, firstFailTime should be set to the second failed login time. I can’t manually define 100 variables. Interviewers may turn green. Wish to give me a Mysql data table, every login to save, so that it can be very convenient to find a certain time interval login situation.
Don’t panic, although we are not big guy, but bit by bit analysis or can, calm down! Wait, that was the data store all the login data? I can’t manually create 100 variables, but I can use a data structure to record the time of login failure. The data structure of chronological order can be seen from the data order is not a linked list!! There is also the login authentication problem, which is better to be lazy and use a Boolean control. Solve, cool ~
P.S: That’s just my thinking. There must be a better solution.
P.S: I did not consider opening multiple threads to test, because I personally feel that user login will not occur in the environment of high concurrency, tens of thousands of people log in the same account at the same time is ridiculous…… But I added the synchronize keyword to map just to be safe.
The Person class:
package exam;
import java.util.LinkedList;
/** * Created by Enzo Cotter on 2021/3/10. */
public class Person {
/** * reset time */
private static final int RESET_TIME = 30;
/** * Duration of five consecutive failed attempts */
private static final int DURATION = 10;
/** * Maximum number of input failures */
private static final int MAX_TIMES = 5;
/** * user id */
private String id;
/** * Number of login failures */
private int failCount;
/** * The first failure time */
private long firstFailTime;
/**
* 登录失败的时间
*/
private LinkedList<Long> times;
private boolean lock;
public String getId(a) {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getFailCount(a) {
return failCount;
}
public void setFailCount(int failCount) {
this.failCount = failCount;
}
public long getFirstFailTime(a) {
return firstFailTime;
}
public void setFirstFailTime(long firstFailTime) {
this.firstFailTime = firstFailTime;
}
public LinkedList<Long> getTimes(a) {
return times;
}
public void setTimes(LinkedList<Long> times) {
this.times = times;
}
public Person(a) {}public Person(String id, int failCount, long firstFailTime, LinkedList<Long> times, boolean lock) {
this.id = id;
this.failCount = failCount;
this.firstFailTime = firstFailTime;
this.times = times;
this.lock = false;
}
/** * Enter this method */
public void isValid(a){
long thisTime = System.currentTimeMillis() / 1000;
System.out.println("First login failed time" + thisTime);
// Reset after 30 minutes
if(thisTime > firstFailTime + RESET_TIME){
this.failCount = 1;
firstFailTime = thisTime;
times = new LinkedList<>();
times.addLast(thisTime);
this.lock = false;
return;
}else{ // No more than 30 minutes
if (lock){
System.out.println("Account locked, please" + RESET_TIME + "Come back in a minute.");
return;
}
// The first login failed 10 minutes ago
while(! times.isEmpty() && thisTime > times.getFirst() + DURATION){ times.removeFirst();this.failCount --;
this.firstFailTime = times.isEmpty() ? thisTime : times.getFirst();
}
if(this.failCount >= 5 && thisTime < firstFailTime + DURATION){
System.out.println("Login failed due to incorrect password for more than 5 times within 10 minutes.");
times.addLast(thisTime);
this.lock = true;
}else if(failCount < MAX_TIMES){
this.failCount ++;
System.out.println("Password error" + this.failCount + "Time"); times.addLast(thisTime); }}}}Copy the code
The main class:
package exam;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/** * Created by Enzo Cotter on 2021/3/10. */
public class FlowLimit {
private static Map<String, Person> map = new HashMap<>();
/** * login *@param id
* @paramFlag Whether the flag is successful */
public static void login(String id, boolean flag){
if (flag){
// Successful login
return;
}else{
Person p = null;
// Login failed
synchronized (map) {
p = map.get(id);
if (p == null){
p = new Person(id, 0, System.currentTimeMillis() / 1000.new LinkedList<>(), false);
map.put(id, p);
return; } p.isValid(); }}}public static void main(String[] args) {
for(int i = 0; i < 20; i ++){
login("aaa".false); }}}Copy the code