Ant E-commerce Bank test launch, the first two rounds of face-to-face experience sharing (Java)

Code question: Given an array, output the kth largest number

You can solve this problem using the Quickselect algorithm, which is similar to the quicksort algorithm, except that it only needs to sort a part of the array.

Here are the steps to quickly select the algorithm:

Randomly select an element from the array as the pivot.

Move elements in the array that are smaller than the pivot value to the left of the array, and elements greater than the pivot value to the right of the array.

If the index of the base value is k-1, return that element.

If the subscript of the reference value is greater than k-1, continue to search for the kth largest element on the left of the reference value.

If the subscript of the reference value is smaller than k-1, continue to search for the kth largest element on the right of the reference value.

import java.util.Random;
public class Solution {
    public int findKthLargest(int[] nums, int k) {
        return quickselect(nums, 0, nums.length - 1, k);
    }

    private int partition(int[] nums, int left, int right) {
        Random random = new Random();
        int pivotIndex = random.nextInt(right - left + 1) + left;
        int pivot = nums[pivotIndex];
        swap(nums, pivotIndex, right);
        int storeIndex = left;
        for (int i = left; i < right; i++) {
            if (nums[i] > pivot) {
                swap(nums, i, storeIndex);
                storeIndex++;
            }
        }
        swap(nums, storeIndex, right);
        return storeIndex;
    }

    private int quickselect(int[] nums, int left, int right, int k) {
        if (left == right) {
            return nums[left];
        }
        int pivotIndex = partition(nums, left, right);
        if (pivotIndex == k - 1) {
            return nums[pivotIndex];
        } else if (pivotIndex > k - 1) {
            return quickselect(nums, left, pivotIndex - 1, k);
        } else {
            return quickselect(nums, pivotIndex + 1, right, k);
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];

The types of java collections, the underlying implementation of HashMap, and what is the loading factor? why this value

Commonly used collections in Java are List, Set, Queue, and Map. The implementation classes of the List interface include ArrayList and LinkedList, the implementation classes of the Set interface include HashSet and TreeSet, the implementation classes of the Queue interface include LinkedList and PriorityQueue, and the implementation classes of the Map interface include HashMap and TreeMap.

Let's focus on explaining the underlying implementation and loading factor of HashMap.

HashMap is implemented based on a hash table. Its underlying data structure is an array and a linked list (or a red-black tree). The hash function is used to map keys to indexes to achieve fast insertion, lookup, and deletion operations.

Specifically, a hash function maps the key of a key-value pair to an integer, which can be used as an index into an array. In order to deal with conflicts, that is, different key-value pairs are mapped to the same array index, HashMap uses a linked list or a red-black tree to store these key-value pairs. When the length of the linked list exceeds the threshold (8), the linked list will be converted into a red-black tree.

The load factor of HashMap refers to the ratio of the number of key-value pairs in the hash table to the length of the array. When the number of key-value pairs in the hash table exceeds the product of the array length and the load factor, HashMap will expand the capacity. , that is, recreate a larger array and rehash all key-value pairs into the new array. The time complexity of this operation is O(n), where n is the number of key-value pairs.

By default, the loading factor of HashMap is 0.75, which is a more appropriate value and can achieve a balance in time and space. If we want higher performance, we can reduce the load factor, but this will increase the space occupied; conversely, if we want to reduce the space occupied, we can increase the load factor, but this will increase the hash collision probability of degrading performance.

In the scenario where you usually use threads, what do you think is the difference between using multithreading and multiprocessing in your scenario?

The relationship between threads and the bottom layer of the process, whether the thread can use the multi-core of the CPU.

Processes and threads are concepts in the operating system to manage and schedule computer resources. A process is an execution process of a program in the operating system, and is the basic unit of resource allocation and scheduling; while a thread is an execution unit in a process, and is also the basic unit of operating system scheduling. A process can contain multiple threads, and these threads can share the resources of the process, such as memory, files, and so on. Threads are lightweight, and they can execute concurrently within the same process, thereby improving program performance.

In the underlying implementation, each thread is managed and scheduled by the operating system kernel. Threads have their own state such as stack space, program counter, and registers, but they share the address space and other resources of the process.

When a process is created, it has a main thread. The main thread can create other threads and can access the resources of the process. Different threads can be executed on different CPU cores, so that multi-core CPUs can be used to improve the concurrent performance of the program.

Generally speaking, thread and process are two basic concepts in the operating system. Thread is the execution unit in the process and can share the resources of the process. Threads can use multiple cores of the CPU to execute concurrently, thereby improving the performance of the program.

Project-related issues, a brief introduction to the test-related work done

The ACID characteristics of transactions, with examples to illustrate these four characteristics

The ACID characteristics of transactions refer to Atomicity, Consistency, Isolation and Durability, which are four important characteristics to ensure the correctness, reliability and security of database transactions.

Atomicity: A transaction is an indivisible sequence of operations. All operations in a transaction are either executed successfully, or rolled back to the state before the transaction started. For example, the two steps of deduction and transfer in a bank transfer operation must either succeed at the same time, or fail and rollback at the same time.

Consistency: It means that before and after the execution of the transaction, the integrity constraints of the data are not violated. For example, a bank account cannot have a negative balance. If a transfer operation results in a negative balance, then this operation does not meet the consistency requirements.

Isolation: means that the execution of transactions cannot affect each other, and each transaction should be logically executed independently, as if it were the only operation. For example, if two users transfer funds to the same bank account at the same time, they should not interfere with each other.

Durability: Once the transaction is committed, the changes made to the data are permanent, even if the system fails, the data will not be lost. For example, if the status of an order changes from "pending payment" to "paid", this status change should be permanently saved and cannot be lost even if the database crashes.

To sum up, ACID characteristics play a very important role in the correctness and reliability of database transactions. Through these four characteristics, the correctness, reliability and security of data can be ensured, thereby ensuring the normal operation of the business system.

Do you know about distributed transactions? talk about your understanding

Distributed transactions refer to transaction operations involving multiple independent systems or multiple databases. Since these systems and databases may be located on different servers, there will be a certain delay in communication between them, and each system or database has its own transaction management mechanism, therefore, special techniques are required to ensure transactions between these systems Consistency and correctness of operation. Here are some common distributed transaction solutions:

Two-phase commit (2PC): 2PC is the most common distributed transaction solution. Here's how it works: First, the transaction coordinator sends a "ready" request to all participants and waits for a response from all participants. If all participants are ready, the transaction coordinator sends a "commit" request, otherwise a "rollback" request.

Compensating Transaction: Compensating Transaction is another common distributed transaction solution. It works like this: when a participant fails, all other participants perform a special "compensation" operation that undoes the previous operation, thus rolling back the entire transaction.

3PC (Three-Phase Commit): 3PC is an improved version of 2PC, which adds a "timeout" phase to solve the "blocking" problem in 2PC. In 3PC, if a participant fails in the "ready" phase, the transaction coordinator will send an "abort" request to all other participants, so that all participants will perform compensation operations.

TCC (Try-Confirm-Cancel): TCC is a relatively new distributed transaction solution. Its working principle is: in a distributed system, each participant implements a TCC interface, which contains "try" , "Confirm" and "Cancel" three methods. When the transaction is executed, first execute the "try" method to check whether all participants are ready, if they are ready, execute the "confirm" method, otherwise execute the "cancel" method.

In conclusion, it is not easy to implement transaction operations in distributed systems, and special techniques and solutions are required to ensure their correctness and consistency. The above are some common distributed transaction solutions. Each solution has its advantages and disadvantages, and it is necessary to choose the appropriate solution according to the actual situation.

If you are asked to do something that was difficult at the time, how do you think you can optimize it?

I would consider the following optimization strategies:

1. Make a clear plan: Making a clear, specific, and executable plan can help me break down complex tasks, divide it into several small steps, and gradually complete the goal.

2. Find appropriate resources: I will look for some appropriate resources to help me complete the task, such as: reading relevant literature, participating in relevant training, consulting with experts, discussing with colleagues, using tools and technologies, etc.

3. Manage time: I break down tasks into actionable steps and allocate appropriate time to complete each step. In the meantime, I set aside some time for adjustments and unforeseen circumstances.

4. Improve efficiency: I will try to use some efficient methods to complete tasks, such as using tools to automate repetitive operations, parallel processing of multiple tasks, and so on.

5. Continuous learning: For me, learning is the key to improving efficiency and overcoming difficulties. I will keep learning new knowledge and skills in order to better deal with challenges.

In short, when faced with a difficult problem, I will adopt some optimization strategies to enable myself to complete tasks more efficiently while continuing to learn and grow.

Then there is the rhetorical questioning session: business content, etc.

3.28 two sides: telephone interview, about an hour

First self-introduction followed by cross-examination of the project

Design test cases for your own project; asked some front-end ones (did not answer)

http status code

The HTTP (Hypertext Transfer Protocol) status code is a 3-digit code used to indicate that the web server responds to the HTTP request. These status codes are divided into 5 categories:

1xx (Information): The received request is being processed and further action is required.

2xx (Success): The request was successfully received, understood, and accepted.

3xx (Redirect): Further action is required to complete the request. For example, the browser needs to be redirected to another URL.

4xx (Client Error): The client request contained syntax errors or could not complete the request. For example, 404 Not Found means that the requested URL was not found on the server.

5xx (Server Error): The server was unable to complete a valid response to the request. For example, 500 Internal Server Error means that the server encountered an internal error while trying to process the request.

The following are some common HTTP status codes:

200 OK: The request was successful

201 Created: The new resource has been successfully created

301 Moved Permanently: The requested URL has been permanently moved to a new location

400 Bad Request: There is a syntax error in the client request

401 Unauthorized: The request is unauthorized

403 Forbidden: The server refuses to provide the requested resource

404 Not Found: The server cannot find the requested resource

500 Internal Server Error: Internal server error

503 Service Unavailable: The server cannot process the request because the server is overloaded or due to maintenance

The parameters passed by the get request are placed in the header or body of the http request

Generally speaking, the parameters passed by the GET request are passed in the form of a query string (query string) by placing the parameters after the URL of the HTTP request, rather than in the request header (header) or request body (body).

For example, the following URL contains two parameters:

https://example.com/search?q=keyword&page=2

Among them, qand pageare the parameter names, keywordand 2are the corresponding parameter values. These parameters will be encoded and placed in the query string of the URL, which is ?the following string.

The request body of a GET request usually does not contain data, because the request body is mainly used to transfer data in request methods such as POST and PUT. In practical applications, the parameters of the GET request can also be placed in the request header, but it is not commonly used, and the HTTP standard does not specify which field in the request header the parameters of the GET request must be placed in. Therefore, it is generally recommended to put the parameters of the GET request in the query string of the URL.

The data storage form of mysql database; why use b+ tree?

In the MySQL database, data is stored in the form of pages, and the default size of each page is 16KB. A page can store multiple records, and the space occupied by each record is different, but the total space must not exceed the size of the page.

A variety of data storage engines are used in MySQL, among which the InnoDB engine is the most commonly used one. The data storage of the InnoDB engine adopts the data structure of B+ tree, which is used to realize the index and fast search of data.

B+ tree is a multi-way search tree, each node can have multiple child nodes, and can store multiple data items. The characteristic of B+ tree is that all data are stored in leaf nodes, and non-leaf nodes only store index information. At the same time, the leaf nodes of the B+ tree are connected in order from small to large to form an ordered linked list, which can quickly implement range query and sorting operations.

Using B+ tree as the data storage structure in MySQL can bring the following advantages:

Efficient search: The structure of the B+ tree ensures high search efficiency, and each search only needs to perform O(log n) comparison operations.

Orderliness: The leaf nodes of the B+ tree are connected in ascending order, enabling range query and sorting operations.

Support high concurrency: The structure of B+ tree supports high concurrency, and data can be shared between multiple threads.

Suitable for large-scale data storage: The B+ tree structure is suitable for storing large-scale data and can effectively use disk space.

In short, B+ tree is an efficient and orderly data storage structure, and its application in MySQL can improve data query efficiency, support high concurrency, and be suitable for large-scale data storage.

Index design question: There are three separate columns of abc in the data table, among which A&B, B&C, and A, B, and C are the five most frequent queries. How would you design the index?

To solve this problem, the following index design scheme can be considered:

For the query of the combination conditions of AB and BC, a joint index (AB, BC) or (BC, AB) can be created. This can ensure that the query for the combined conditions of AB and BC can quickly locate the corresponding records and avoid full table scanning.

A single-column index can be created for separate queries with three conditions A, B, and C. In this way, qualified records can be quickly located and full table scans can be avoided.

Combining the above two solutions, the following indexes can be created:

(A,B) Create a joint index to support A and B and A index queries

(B,C) Create a joint index to support B and C and B index queries

(C) Create a single-column index to support queries against C conditions.

It should be noted that when designing an index, the creation cost and maintenance cost of the index need to be considered. Too many indexes will increase the burden on the database, so trade-offs and choices need to be made according to the actual situation. In addition, in practical applications, the impact of data update and deletion operations on the index needs to be considered, and the index type and creation method need to be reasonably selected.

Test scenario question: If you are a quality inspector of a toy company, how would you ensure the quality of toys in terms of process control and use case design.

As a quality inspector of a toy company, my job responsibility is to ensure that there are no problems in the manufacturing process of the toy, and that the quality of the final delivered product is high and safe. In terms of process control and use case design, I will take the following measures to ensure the quality of toys:

1. Process control: I will regularly check and evaluate the company's production and testing process to check for any shortcomings and deficiencies that may affect product quality. If deficiencies are found, I would advise the company to address them using best practices to ensure quality and continuity of the production process.

2. Use case design: I will develop a set of detailed use case designs for each toy to ensure that each step in the production process is checked and verified. These test cases will cover the whole process from supplying raw materials to manufacturing, packing and dispatching. Use cases will cover key aspects such as dimensions, weight, material composition, product appearance, and more to ensure that each product meets specifications.

3. Sample testing: Samples are also selected from each batch in each production cycle for comprehensive testing and evaluation. These tests will cover various aspects such as product quality and safety, structural integrity and comfort of the product and many more. Data from the tests performed will help us identify any quality issues in the manufacturing process and be able to trace back possible causes of quality issues.

In short, by doing the above three points well, we can effectively control quality risks, ensure product quality and safety, and ensure that toys can achieve excellent sales results.

The problem of producers and consumers is mainly to solve what kind of problem?

"Producer-consumer problem" refers to the synchronization problem of the buffer between the producer and the consumer in multi-threaded programming, where the producer is the thread that produces data to the buffer, and the consumer consumes data from the buffer thread. The main problem is that producers and consumers need to access the same resource, that is, the shared buffer, but the execution speed and order of producers and consumers may not be the same, and the following problems may exist:

1. The producer may try to add data when the buffer is full, causing a deadlock. A deadlock is a state in which multiple processes or threads are caught in an infinite wait due to competition for the same resource.

2. Consumers may try to consume data when the buffer is empty, which will also cause deadlock. The solution to the problem is to use a synchronization mechanism for control to prevent producers and consumers from accessing the buffer at the same time, ensuring that the buffer is in a normal state at all times. Among them, the most commonly used synchronization mechanisms are semaphores and mutexes.

Specifically, by introducing a semaphore or a mutex between the producer and the consumer, the mutual exclusion of access to shared resources (ie, buffers) can be guaranteed, and multiple threads can safely access the same resource.

For example, when the buffer is full, the producer process can wait on a semaphore or mutex until space is available, and then wake up the producer thread to produce after there is space.

Similarly, when the buffer is empty, the consumer process can wait on the semaphore or mutex until data is available, and then wake up the consumer thread to consume after the data is available. Since the producer-consumer problem arises frequently in multithreaded programming, it needs to be discussed and resolved for correctness and efficiency with any multithreaded application.

Conditions that lead to deadlock

Deadlock refers to a state in which multiple threads or processes hold their own locks and wait for Hold other locks, resulting in the inability to continue running. The following four conditions must be met at the same time to cause a deadlock:

1. Mutually exclusive conditions: at least one resource is exclusive. When multiple threads or processes need to use these resources, only one thread or process can occupy the resource, while other threads or processes must wait for the resource to be released.

2. Request and hold conditions: A process that has already connected to a resource applies for a new resource, but because the resource it holds has not been released, the application for a new resource is blocked. At the same time, other processes want to acquire the resource, but because it is held by this process, it is also blocked.

3. Non-alienable conditions: In some cases, resources that a process has acquired cannot be forcibly taken away. This means that the system can release resources only after the process has completed all the resources it occupied.

4. Circular waiting condition: There is a circular waiting for resources. That is to say, one process waits for resources held by another process, and the process is waiting for resources held by other processes, thus forming a circular dependency, and the process cannot continue to execute. Note that in the absence of any of these conditions, no deadlock will occur.

Therefore, in order to avoid deadlocks, appropriate measures can be taken according to these conditions, such as releasing resources periodically or introducing a timeout mechanism, etc.

The understanding of optimistic locking and pessimistic locking, examples of optimistic locking and pessimistic locking in java?

In concurrent programming, optimistic locking and pessimistic locking are two strategies for dealing with shared resources. Pessimistic Lock (Pessimistic Lock, referred to as P lock) is a pessimistic strategy. It believes that during the entire process of shared resources being processed, they may be accessed and modified by other threads. Add a lock to ensure that your own thread has exclusive access.

The common pessimistic locking mechanism in Java is synchronized, which can ensure that only one thread holds the lock at the same time, and other threads need to wait to acquire the lock to access shared resources, so as to ensure the consistency of shared resources. An example of pessimistic locking in Java: use the synchronized keyword to lock shared resources, so that when threads access shared resources, they can monopolize shared resources. For example, the following code uses the pessimistic locking mechanism:

public class ExampleThread implements Runnable {
    private int count;

    public void run() {
        synchronized(this) {
            for(int i=0;i<5;i++) {
                count++;
                System.out.println(Thread.currentThread().getName() + " count:" + count);
            }
        }
    }
}

2. Optimistic lock In contrast, optimistic lock (Optimistic Lock, referred to as O lock) is an optimistic strategy. It believes that in the whole process, shared resources are rarely occupied by other threads, so they can directly access shared resources, while No need to lock. Only when it is actually updated will it check whether there is a conflict, and if a conflict is detected, it will be returned to the application layer for processing.

The common optimistic locking mechanism in Java is CAS (Compare and Swap), which can realize atomic operations on shared variables without locking. When multiple threads try to update the same shared variable, only one of the threads can The update is successful, other threads need to retry or wait. This can avoid the impact of lock competition on performance and improve the efficiency of concurrency. An example of optimistic locking in Java: the case where multiple threads operate on the same resource at the same time through the CAS principle. For example, the following code uses the optimistic locking mechanism:​​​​​​​​

public class ExampleThread implements Runnable {
    private AtomicInteger count = new AtomicInteger(0);

    public void run() {
        for (int i = 0; i < 5; i++) {
            int val = count.incrementAndGet();
            System.out.println(Thread.currentThread().getName() + " count " + val);
        }
    }
}

The above are the basic concepts of optimistic locking and pessimistic locking and examples in Java. It is necessary to choose a suitable locking mechanism according to different scenarios and applications to obtain better performance and ensure the consistency of shared resources.

How to solve the ABA problem of optimistic lock CAS, atomic class

CAS (Compare and Swap) is an implementation of optimistic locking, which can achieve concurrency security without locks. However, in the case of multithreading, "ABA" problems may arise.

The "ABA" problem means that after a thread reads a certain data, before performing the CAS operation, the value of the data is modified multiple times by other threads, and finally modified back to the original value. In this case, the CAS operation will be wrong. It is considered that the variable has not been modified, so the modification operation will also be performed.

To solve the "ABA" problem, mechanisms such as version numbers or timestamps can be used. When using CAS for data comparison, in addition to comparing the value of the variable, it is also necessary to compare the version number of the variable. If the current version number is inconsistent with the compared version number, it means that the variable has been modified by other threads, and the CAS operation cannot be performed.

For example, AtomicStampedReference and AtomicMarkableReference in Java use the version number mechanism to solve the ABA problem.

What is the underlying implementation of CAS?

CAS (Compare and Swap) is an implementation of optimistic locking, which is used to solve the concurrency problem when multiple threads modify the same data concurrently.

The CAS operation contains three operands, the memory address V, the old expected value A and the new value B. The specific working principle is as follows:

1. When performing a CAS operation, first read the value of the current memory address V.

2. If the current value is different from the old expected value A, the operation fails and the operation is terminated.

3. If the current value is the same as the old expected value A, update the value of the memory address V to the new value B.

4. If it is found that the value of the memory address V has changed during the operation, that is, it has been modified by other threads, repeat the operations from Step 1 to Step 3 until the value is updated successfully.

In Java, CAS operations can use the Unsafe class for underlying implementation. The Unsafe class provides methods to directly manipulate memory data, including obtaining memory addresses, reading the value of memory addresses, and CAS operations. Since the underlying implementation of the Unsafe class is based on hardware operations, it has extremely high performance.

Java provides some atomic classes (such as AtomicInteger, AtomicLong, AtomicBoolean, etc.), which are implemented based on CAS. For example, when multiple threads call the incrementAndGet() method of the AtomicInteger instance at the same time, the underlying implementation uses CAS to ensure data concurrency security. Of course, since the implementation of CAS operations must use the support of the underlying hardware, the use of CAS operations in Java is also limited, and not all JVMs support this operation. If the JVM does not support Unsafe and CAS operations, you need to manually implement CAS operations in other ways.

For example, use synchronized to lock some code blocks, etc. All in all, in concurrent programming, CAS is a very important technology, which can improve the concurrent performance of the program to a certain extent. Understanding the underlying CAS implementation principles will help us better understand the mechanism of Java concurrency and better solve concurrency problems.

Test scenario question: Test Tmall's discount mechanism: Xiao Er will write the discount policy into the database before the discount starts, and the system will read it into the cache; when the discount takes effect, you can consider the test points to ensure that the entire The process works correctly. (two angles, minor two angle; user angle)

The following examples are for reference only and considered from the perspective of a child:

1. Verify that when Xiao Er writes into the database, whether the preferential policy is correctly written, and whether the preferential policy meets the requirements, including but not limited to discount rate, full discount rules, etc.

2. Verify that the process of filling in the policy for the second child is normal, including but not limited to the UI of filling in the policy, the process of filling in the policy, etc.

3. Verify that after the preferential policies are written into the database, whether they can be read correctly and stored in the cache correctly, and if the cache fails, can they be reloaded correctly.

4. Verify that Xiao Er can modify, delete and other operations before the policy takes effect, and whether the policy can be properly sealed and terminated after modification.

5. When writing preferential policies, concurrency needs to be considered, such as writing the same policy at the same time, and it is necessary to verify whether it can work normally under concurrent conditions and whether the number of writes is accurate.

From the user's point of view:

1. Verify whether the user can correctly obtain the currently applicable discount strategy, and whether the discounted amount has been correctly reflected when the user purchases.

2. Verify whether the user can cancel the offer before payment, and whether it can correctly reflect the status of the offer being canceled, and whether the payment amount needs to be recalculated.

3. Verify that during the purchase process, if the preferential policy expires or is modified, whether the user can be notified correctly and an appropriate solution is provided.

4. Verify that users can get clear instructions and help when writing discount policies, and can know whether the discounts they enjoy are compliant and reasonable, and whether there are other more favorable options.

5. When abnormal situations such as abnormalities and errors occur, can they be adjusted and dealt with in time to avoid affecting the normal use of users.

Finally, there is the question section.

Finally:  The complete software testing video learning tutorial below has been sorted out and uploaded, and friends can get it for free if they need it【保证100%免费】

insert image description here

 These materials should be the most comprehensive and complete preparation warehouse for [software testing] friends. This warehouse has also accompanied tens of thousands of test engineers through the most difficult journey. I hope it can help you too!

Guess you like

Origin blog.csdn.net/weixin_50829653/article/details/130485261