Объектно-ориентированные три характеристики и семь принципов
Объектно-ориентированные три характеристики и семь принципов
Три характеристики
упаковка
封装Это класс-носитель для атрибутов и методов, доступ к которым возможен только через предоставленный им интерфейс (метод) и скрывает детали реализации Конкретная реализация прозрачна для программиста Преимущество инкапсуляции заключается в изменениях внутри класс, не влияет на другой код
- Практика инкапсуляции: частные свойства (частные модификаторы изменяют свойства), предоставление общедоступных методов чтения (getXX) и записи (setXX), а также методы вызова при построении.Все непостоянные свойства в основном должны быть инкапсулированы.
- Преимущества инкапсуляции: скрыть детали реализации класса, предоставить унифицированный интерфейс для всех пользователей, улучшить эффект выполнения, легко поддерживать и расширять.
наследовать
继承Это отношение, которое логически удовлетворяет отношениям между родительскими подклассами IS A. Подклассы наследуют свойства и не частные методы родительского класса. Не могут наследовать текстуру родительского класса, наследовать использование ключевых слов, расширение, наследование класса, Интерфейс Много наследования.
- При построении объекта подкласса вызовите конструкцию родительского класса в свою очередь (подкласс вызывает по умолчанию конструкции родительского класса без параметра. Вы можете использовать Super (список параметров) для вызова указанного параметра, содержащего параметры родительского класса). До объекта. Затем позвоните под подклассом сам класс; когда подкласс вызывает конструктор родительского класса, конструктор родительского класса может звонить только по одному, и он должен быть записан в первом предложении конструктора подкласса.
полиморфизм
多态Относится к разрешению объектам разных классов отвечать на одно и то же сообщение. Полиморфизм включает параметрический полиморфизм и полиморфизм включения. Полиморфный язык обладает преимуществами гибкости, абстракции, совместного использования поведения и совместного использования кода, а также решает проблему одноименных функций приложения.Существует четыре типа полиморфизма:
Полиморфизм основных типов: распаковка, бокс.
По сути, это автоматическое преобразование типов между базовыми типами.В языке Java каждый из восьми типов данных инкапсулирован в класс, и эти классы инкапсулируют атрибуты и основные операции каждого базового типа данных.
Операция автоматического преобразования базового типа в соответствующий инкапсулированный класс называется операцией автоматической упаковки, иначе она называется операцией автоматической распаковки.Операция автоматической упаковки имеет автоматический пул упаковки (диапазон -128~127). количество автоматических боксов находится в рамках пула автоматической упаковки, перейдите непосредственно к пулу, чтобы найти данные.
Полиморфизм методов: перегрузка, переопределение.
-
Переопределение: когда метод, унаследованный родительским классом, не подходит для подкласса, подкласс может изменить реализацию метода.Эта операция называется переопределением/переопределением метода (наследование является обязательным условием для переопределения); требования переопределения:
- Возвращаемое значение, имя метода и параметры одинаковы ((после версии 5.0 разрешено возвращать типы подклассов));
- Исключения подкласса не могут превышать исключения родительского класса;
- Уровень доступа подкласса не может быть ниже уровня доступа родительского класса.
-
Перегрузка: Перегрузка — это наличие двух или более методов с одинаковым именем в одном классе, но с разными параметрами (разное количество параметров, разные типы, разный порядок ), и тело метода также отличается. Тип возвращаемого значения может быть одинаковым или различным. Наиболее распространенным примером перегрузки является конструктор.
Полиморфизм класса или интерфейса: ссылка на родительский класс указывает на объект дочернего класса
Направляющий объект Ссылаченный подкласс родительского класса (человек p = новый студент ()) полиморфизм, происходит в этом сценарии:
- Можно использовать только свойства и методы, определенные в родительском классе.
- Определенные в подклассах нельзя использовать напрямую
- Подкласс перезаписывает метод родительского класса.В настоящее время ситуация вызова различается в зависимости от того, является ли метод статическим или нет [статическим (вызов родительского класса), нестатическим (вызовом подкласса)].
- Если вы хотите использовать метод, определенный в подклассе, вы можете принудительно преобразовать тип (чтобы определить, можно ли его преобразовать, используйте
instance ofоператор для определения типа объекта)
Пример программы
class A {
int a = 1;
static int b = 20;
int c = 3;
double d = 2.0;
void show() {
System.out.println("Class A: a=" + a + "\td=" + d + "\tc=" + c + "\tb=" + b);
}
void common(){
System.out.println("Class A: method common()");
}
static void execute(){
System.out.println("Class A: method excute()");
}
}
class B extends A {
float a = 3.0f;
static int b = 30;
int c = 5;
String d = "Java program.";
void show() {
super.show();
System.out.println("Class B: a=" + a + "\td=" + d + "\tc=" + c + "\tb=" +b);
}
void common(){
System.out.println("Class B: method common()");
}
static void execute(){
System.out.println("Class B: method execute()");
}
public static void main(String[] args) {
A a = new B();
a.show();
System.out.println("----------------------");
a.common();
System.out.println("----------------------");
a.execute();
}
}
Выполнить вывод
Class A: a=1 d=2.0 c=3 b=20
Class B: a=3.0 d=Java program. c=5 b=30
----------------------
Class B: method common()
----------------------
Class A: method excute()
Полиморфизм при передаче параметров
[Вопрос интервью] Является ли передача параметров в Java проходной или по ссылке?
Вызов метода в языке Java поддерживает только передачу параметров по значению.Когда экземпляр объекта передается в качестве параметра методу, значение параметра является ссылкой на объект. Свойства объекта могут быть изменены во время вызываемого процесса, но изменения ссылки на объект не повлияют на вызывающую программу.
Пример программы
public class Test {
public static void invoke(int num, Person person){
num = 222;
person.setAge(20);
person.setName("李四");
System.out.println(num + "," + person.getName() + "," + person.getAge());
}
public static void main(String[] args) {
int num = 111;
Person person = new Person("张三", 10);
invoke(num, person);
System.out.println(num + "," + person.getName() + "," + person.getAge());
}
@Data
static class Person{
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private String name;
private int age;
}
}
вывод программы
222,李四,20
111,李四,20
семь принципов
- Принцип единой ответственности (класс делает только то, что должен делать),
- Принцип «открыто-закрыто» (закрыт для модификации, открыт для расширения),
- Принцип инверсии зависимостей (интерфейсно-ориентированное программирование),
- Принцип замещения Лискова (подтипы могут быть использованы для замены супертипов в любое время),
- Принцип изоляции интерфейса (интерфейсы должны быть небольшими и специализированными, а не большими и полными),
- Принцип синтетического повторного использования (предпочтительно использовать агрегацию или код повторного использования синтетических отношений),
- Принцип Димитриса (между объектом и объектом должно использоваться как можно меньше способов связи)
Порядок инициализации программы Java
Последовательность инициализации программы Java
При создании экземпляра объекта на языке Java сначала должны быть созданы все переменные-члены класса, в котором находится объект, и только после того, как будут созданы экземпляры всех членов класса, будет вызван конструктор класса, в котором находится объект. создать объект; инициализация программы Java обычно следует 3 принципам (уменьшение приоритета):
- 1) Статические объекты (переменные) инициализируются, а не нестатические объекты (переменные).
- 2) Классификация имеет приоритет над подклассами для инициализации.
- 3) Переменные-члены инициализируются в том порядке, в котором они определены. Даже если определения переменных разбросаны по определениям методов, они все равно инициализируются до вызова каких-либо методов (включая конструкторы).
Пример программы
class B {
static {
System.out.println("B with static ");
}
{
System.out.println("B with code block");
}
public B(){
System.out.println("B with construct");
}
}
class A extends B {
static {
System.out.println("A with static");
}
{
System.out.println("A with code block");
}
public A(){
System.out.println("A with construct");
}
}
Вариант использования сценария 1:
public class Test {
public static void main(String[] args) {
new B();
System.out.println("------");
new B();
}
}
Выход сценария 1:
B with static
B with code block
B with construct
------
B with code block
B with construct
Вариант использования сценария 2:
public class Test {
public static void main(String[] args) {
new A();
}
}
Вывод сценария 2:
B with static
A with static
B with code block
B with construct
A with code block
A with construct
Вариант использования сценария 3:
public class Test {
public static void main(String[] args) {
new A();
System.out.println("------");
new A();
}
}
Выход сценария 3:
B with static
A with static
B with code block
B with construct
A with code block
A with construct
------
B with code block
B with construct
A with code block
A with construct
Типы переменных в языке Java
Типы переменных в языке Java
В языке Java существует всего три типа переменных:成员变量,静态变量и局部变量.
Переменные-члены
Область действия переменной-члена класса совпадает с областью действия экземпляра объекта класса.При создании экземпляра класса переменной-члену будет выделено место в памяти и инициализирована до окончания жизненного цикла созданного объекта. цикл окончен.
Существует четыре типа областей действия переменных-членов класса, а также области прав доступа от больших до малых:public > protected > default > private.
- public: Указывает, что переменная или метод элементов видимы для всех классов или объектов, и все классы или объекты могут напрямую доступ к нему.
- protected: указывает, что переменная-член или метод видимы для себя и своих подклассов, а другие классы или объекты не имеют прав доступа.
- default: указывает, что переменная-член или метод видны только себе и классу в одном пакете.Если родительский класс и подкласс находятся в разных пакетах, разрешения на доступ нет.
- private: Указывает, что переменная-член или метод являются закрытыми, только текущий класс имеет права доступа к ним, другие классы или объекты не имеют прав доступа.
Уведомление: эти модификаторы могут изменять только переменные-члены, но не локальные переменные. Private и protected нельзя использовать для изменения классов (для изменения классов можно использовать только public, abstract или final).
статическая переменная
Будьте модифицированной переменной статической элемент-члена, называемые статическими или глобальными переменными, а разница переменных элементов заключается в том, что статические переменные не зависят от определенного экземпляра, но совместно используются всеми случаями; то есть: до тех пор, пока класс загружен, JVM на статический Переменные классов выделит пространство для хранения, поэтому вы можете получить доступ к статической переменной через имена класса и переменной.
локальная переменная
Область действия и видимость локальной переменной заключены в фигурные скобки, в которые она помещена.
Понимание Java — битовые операции
Битовые операторы в основном для бинарных, к ним относятся: «и», «не», «или», «исключающее или».
базовая единица данных
Прежде чем разбираться в операторах, сначала поймите базовую единицу данных.
- BIT (бит): один бит (наименьшая единица данных), например: 0
- BYTE (байт): 1BYTE = 8BIT, например: 01010110
- КБ (килобайты): 1 КБ = 1024 БАЙТА
- МБ (мегабайт): 1 МБ = 1024 КБ
- ГБ (гигабайты): 1 ГБ = 1024 МБ
- ТБ (терабайт): 1 ТБ = 1024 ГБ
Основные типы данных в Java
Длина данных на разных языках может быть неодинаковой, вот здесь, чтобы представить базовую длину данных на языке Java.
Тип данных и соответствующая длина
| тип | длина |
|---|---|
| boolean | - |
| char | 16bit |
| byte | 8bit |
| short | 16bit |
| int | 32bit |
| long | 64bit |
| float | 32bit |
| double | 64bit |
Пример программы
@Test
public void test(){
// 输出: 1
System.out.println(Byte.BYTES);
// 输出: 2
System.out.println(Short.BYTES);
// 输出: 4
System.out.println(Integer.BYTES);
// 输出: 8
System.out.println(Long.BYTES);
// 输出: 4
System.out.println(Float.BYTES);
// 输出: 8
System.out.println(Double.BYTES);
// 输出: 11111111111111111111111111111110
System.out.println(Integer.toBinaryString(-2));
// 输出: 1111111111111111111111111111111111111111111111111111111111111110
System.out.println(Long.toBinaryString(-2L));
char c = '苏';
// 输出: 苏
System.out.println(c);
}
^ (эксклюзивное или)
Два числа, участвующие в операции, если два соответствующих бита одинаковы (двоичные), результат равен 0, иначе - 1. То есть: 0^0=0, 1^0=1, 0^1=1, 1^1=0
Описание операции
| действовать | бинарный | десятичный |
|---|---|---|
| - | 000000000000000000000000000000001 | 1 |
| - | 000000000000000000000000000000010 | 2 |
^ |
000000000000000000000000000000011 | 3 |
программный тест
@Test
public void test(){
// 输出: 3
System.out.println(1^2);
}
&(и)
Два числа, участвующие в операции, если два соответствующих бита равны 1 (двоичные), результат равен 1, в противном случае результат равен 0. То есть: 0^0=0, 1^0=1, 0^1=1, 1^1=1
Описание операции
| действовать | бинарный | десятичный |
|---|---|---|
| - | 000000000000000000000000000000001 | 1 |
| - | 000000000000000000000000000000010 | 2 |
& |
000000000000000000000000000000000 | 0 |
программный тест
@Test
public void test(){
// 输出: 0
System.out.println(1&2);
}
|(или)
В операции участвуют два числа, если только один из двух соответствующих битов равен 1 (двоичный), то результат равен 1, иначе 0. То есть: 0^0=0, 1^0=1, 0^1=1, 1^1=1
Описание операции
| действовать | бинарный | десятичный |
|---|---|---|
| - | 000000000000000000000000000000001 | 1 |
| - | 000000000000000000000000000000010 | 2 |
或 |
000000000000000000000000000000011 | 3 |
программный тест
@Test
public void test(){
// 输出: 3
System.out.println(1|2);
}
~ (не)
Номер расчета параметра, если бит равен 0 (двоичный), результат равен 1, если бит равен 1, результат равен 0.
Описание операции
| бинарный | десятичный | операция | бинарный | десятичный |
|---|---|---|---|---|
| 000000000000000000000000000000001 | 1 | ~ |
11111111111111111111111111111110 | -2 |
| 000000000000000000000000000000010 | 2 | ~ |
11111111111111111111111111111101 | -3 |
программный тест
@Test
public void test(){
// 输出: -2
System.out.println(~1);
// 输出: 11111111111111111111111111111110
System.out.println(Integer.toBinaryString(~1));
// 输出: -3
System.out.println(~2);
// 输出: 11111111111111111111111111111101
System.out.println(Integer.toBinaryString(~2));
}
Интервью с вопросами о побитовых операциях
[Вопрос интервью] Реализовать обмен двумя номерами
Идея: Когда два числа объединены XOR, будет вычислено промежуточное число (даже если два числа одинаковы, то результат вычисления равен 0, что удовлетворяет), и промежуточная ссылка при обмене может быть использована для этого промежуточного числа .
Код
@Test
public void find(){
int a = 1, b=2;
System.out.println("交换前: a = " + a + ", b = " + b);
a = a ^ b;
b = a ^ b; // ((a^b) ^ b) = a
a = a ^ b; // ((a^b) ^ b) = a
System.out.println("交换后: a = " + a + ", b = " + b);
}
[Вопросы собеседования] Реализация листового строки
Идея: использовать XOR для преобразования старших и младших битов
Код
/**
* @param str 待返转的字符串
* @return 翻转后的字符串
*/
public static String reverse(String str){
char[] chars = str.toCharArray();
int low = 0;
int top = chars.length - 1;
while (low < top){
chars[low] ^= chars[top];
chars[top] ^= chars[low];
chars[low] ^= chars[top];
low++;
top--;
}
return new String(chars);
}
【Вопросы для интервью】Набор чисел, за исключением одного числа, которое встречается только один раз, все остальные числа встречаются 2n раз (n>=1), найдите число.
Анализ: поскольку одни и те же два числа^Результатом является 0, 0^любое число = любое число XOR стопки чисел от первого до последнего, тогда окончательное значение результата — это число, которое встречается только один раз.
Код
@Test
public void findOne(){
int[] arr = new int[] {1, 1, 2, 2, 3, 5, 5, 7, 7, 6, 6};
// 从第一个数标开始
int result = arr[0];
// 以此进行后面的数据的异或运算
for(int i = 1; i < arr.length; i++){
result = result ^ arr[i];
}
// 程序输出: 3
System.out.println(result);
}
[Вопросы для интервью] в java
|и||,&и&&Какая разница
-
&(与): Битовый оператор, также имеет функцию оператора логического бюджета. -
&&(短路与): это просто логический оператор Различия между & и && как логическими операторами заключаются в следующем: -
&: Независимо от того, является ли левая часть & ложной, он продолжит проверку логического значения в правой части. -
&&: Пока левое значение обнаружено как ложное, результат будет оцениваться напрямую, а значение справа не будет проверяться (поскольку «и» имеет ложное значение, а окончательный результат ложный), поэтому эффективность выполнения of && выше, поэтому обычно используется логическая операция &&. -
| (Или) разница с || (короткое замыкание или) похоже на & (с) и && (короткое замыкание и).
Класс объекта в Java.
Класс объекта в Java
Каковы общедоступные методы Object
- 1. метод клонирования
Метод защиты, создающий и возвращающий копию этого объекта, используется для реализации поверхностного копирования объекта, этот метод можно вызывать только в том случае, если реализован интерфейс Cloneable, в противном случае выбрасывается исключение CloneNotSupportedException; В JAVA помимо 8 основных типов параметры передаются по значению, другие параметры объекта класса передаются по ссылке, мы иногда не хотим менять параметры в методе, тогда нам нужно переопределить метод клонирования в классе .
- 2. метод getClass
final метод, который возвращает класс времени выполнения объекта.
- 3. метод toString
Возвращает строковое представление объекта.Этот метод используется чаще и обычно охватывается подклассами.
- 4. завершить метод
Этот метод используется для освобождения ресурсов. Этот метод вызывается сборщиком мусора объекта, когда сборщик мусора определяет, что больше нет ссылок на объект. Подклассы переопределяют метод finalize для настройки системных ресурсов или выполнения другой очистки.
После включения метода finalize объекта никакие дальнейшие действия не предпринимаются до тех пор, пока виртуальная машина Java снова не определит, что к объекту больше не может получить доступ ни один не завершившийся поток, включая возможность выполнения другими объектами или классами, готовыми к выполнению. завершить операцию, при выполнении которой объект может быть отброшен.
Метод finalize вызывается виртуальной машиной Java не более одного раза для любого заданного объекта.
- 5. метод равенства
Этот метод является очень важным. Обычно equals и == не совпадают, но в Object они одинаковы. Подклассы обычно переопределяют этот метод.
- 6. метод hashCode
Этот метод используется для поиска по хэшу, что может уменьшить количество раз, когда при поиске используется равенство.Переопределение метода equals обычно требует перезаписи метода hashCode. Этот метод используется в некоторых коллекциях с хеш-функцией.
в общем надо встретитьсяobj1.equals(obj2)==true1。可以推出obj1.hashCode()==obj2.hashCode()`, но равный hashCode не обязательно соответствует равенству. Однако, чтобы повысить эффективность, мы должны попытаться сделать два вышеуказанных условия как можно более близкими к эквивалентным.
Если вы не переопределите hashCode(), добавление двух равных объектов в HashSet добавит оба объекта.
- 7. wait方法
Метод ожидания заключается в том, чтобы заставить текущий поток ждать блокировки объекта, при этом текущий поток должен быть владельцем объекта, то есть иметь блокировку объекта. Метод wait() ожидает, пока блокировка не будет получена или прервана. wait(long timeout) устанавливает интервал ожидания и возвращает значение, если блокировка не получена в течение указанного времени.
После вызова этого метода текущий поток переходит в спящий режим до тех пор, пока не произойдет следующее событие.
-
- Другой поток вызвал метод уведомления объекта.
- 2) Другие потоки вызвали метод notifyAll объекта.
- 3) Другие потоки вызывают прерывание, чтобы прервать поток.
- 4) Временной интервал истек.
В этот момент поток может быть запланирован, и если он будет прерван, будет выброшено InterruptedException.
- 8. УВЕДОМЛЕНИЕ метод
Этот метод пробуждает поток, ожидающий этого объекта.
- 9. метод notifyAll
Этот метод пробуждает все потоки, ожидающие этого объекта.
продление интервью
[Вопрос интервью] Является ли Java передачей по значению или передаче по ссылке
Java относится к передаче, для базовых типов передается значение, а для ссылочных типов передается адрес указателя.
-
Передача по значению: при вызове метода фактический параметр передает свое значение соответствующему формальному параметру, и изменение значения формального параметра во время выполнения метода не влияет на значение фактического параметра.
-
Передача по ссылке: также известная как передача адреса, ссылка (адрес, а не значение параметра) фактического параметра при вызове метода передается соответствующему формальному параметру в методе, и операция над формальным параметром при выполнении метода на самом деле является фактическим Манипулирование параметрами, изменение значения формальных параметров во время выполнения метода повлияет на значение фактического параметра.
【Вопросы для интервью】Объяснение
final,finally,finalizeразница
-
final: модификатор (ключевое слово) имеет три применения: (1) измененный класс: указывает, что класс не может быть унаследован; (2) измененный метод: указывает, что метод не может быть переопределен; (3) измененная переменная: указывает, что переменная может присваивается только один раз Значение не может быть изменено позже (постоянное)
-
finally: обычно размещаемые после конструкций try...catch... всегда выполняют блок кода (оператор return в try{}, код в finally{} будет выполнен до того, как метод вернется к вызывающей программе), что означает, что программа независимо от того, какое нормальное выполнение или исключение происходит, код здесь может выполняться до тех пор, пока JVM не закрыта, а код для освобождения внешних ресурсов может быть написан в блоке finally.
-
finalize: метод, определенный в классе Object.Java позволяет использовать метод finalize() для выполнения необходимой работы по очистке (например, закрытия соединений, закрытия файлов) до того, как сборщик мусора удалит объект из памяти. Этот метод обычно не вызывается явно, но обычно вызывается сборщиком мусора при уничтожении объекта.Переопределяя метод finalize(), вы можете очистить системные ресурсы или выполнить другую работу по очистке.
【Вопросы для интервью】
equalsи==разница
-
==Сравнение — это адрес памяти (кучи) объекта, хранящегося в памяти переменной (стека), который используется для оценки того, совпадают ли адреса двух объектов, то есть относятся ли они к одному и тому же объекту. Сравнение — это настоящая операция с указателем. -
equalsСравнение заключается в том, равно ли содержимое двух объектов.Поскольку все классы унаследованы от класса java.lang.Object, они применимы ко всем объектам, и equals() может возвращать true или false, в основном зависит от перезаписиequalsЛогика реализации метода.
пример кода
public static void main(String[] args) {
String a = new String("ab"); // a 为一个引用
String b = new String("ab"); // b为另一个引用,对象的内容一样
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一对象
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) { // true
System.out.println("true");
}
}
[Вопрос интервью] Объекты имеют одинаковую ценность
(x.equals(y)为true, но может иметь разные значения хеш-функции?
Если два объекта удовлетворяют равенству, истинно, обаx.equals(y)==true, то его хэш-код должен быть таким же.
Если два объекта имеют одинаковый хэш-код, они не обязательно одинаковы.
[] Сталкиваться с вопросами о том, как разрешить конфликт Hash
Создавая хорошо выполняемую хэш-функцию, столкновения могут быть уменьшены, но, как правило, невозможно полностью избежать столкновений, поэтому разрешение столкновений является еще одним ключевым вопросом в хешировании. Оба создания хэш-стола и поиска хэш-стола сталкиваются с конфликтами, и методы разрешения конфликтов должны быть одинаковыми в обоих случаях. Ниже приводится в следующем создании хеш-таблица в качестве примера, чтобы проиллюстрировать метод разрешения конфликтов. Существует четыре широко используемых метода разрешения конфликтов:
- открытая адресация
он же открытое хэширование
Основная идея такова: когда хеш-адрес p=H(key) ключевого слова key сталкивается, другой хеш-адрес p1 генерируется на основе p, и если p1 все еще конфликтует, другой хэш-адрес p1 генерируется на основе p. , ...; до тех пор, пока не будет найден неконфликтующий хеш-адрес pi, и в нем будет сохранен соответствующий элемент.
Этот метод имеет общую форму перехеш-функции:Hi = ( H(key) + di ) % m 其中 i=1,2,…,n
инструкция:H(key)это хэш-функция,mдлина стола,diЭто называется инкрементной последовательностью.Значение инкрементной последовательности отличается, и соответствующие методы повторного хеширования также различны.В основном существуют следующие три типа:
- Перефразирование линейного зонда
di i=1,2,3,…,m-1Характеристики этого метода таковы: при возникновении конфликта последовательно просматривается следующая единица в таблице, пока не будет найдена пустая единица или не будет произведен поиск по всей таблице.
- Второе исследование и перефразирование
di = 12,-12,22,-22,…,k2,-k2 (k<=m/2)Характеристики этого метода таковы: при возникновении конфликта обнаружение перехода выполняется на левой и правой сторонах таблицы, что является более гибким.
- Перефразирование псевдослучайного зонда
di = 伪随机数序列
Пример описания
Например: известная длина хеш-таблицы m=11, хэш-функция:H(key) = key % 11, затем H(47)=3, H(26)=4, H(60)=5, при условии, что следующее ключевое слово равно 69, затем H(69)=3, что противоречит 47.
-
Используйте линейное обнаружение и повторное хеширование для устранения конфликтов: следующий хэш-адрес — H1=(3 + 1) % 11 = 4, конфликт все еще существует, а затем найдите следующий хэш-адрес как H2 = (3 + 2) % 11 = 5. Если конфликт все еще существует, продолжайте поиск следующего хэш-адреса, как H3=(3 + 3)% 11 = 6. На данный момент конфликта нет, и заполните 69 в 5-м блоке.
-
Используйте вторичное обнаружение и хеширование для устранения конфликтов: следующий хэш-адрес — H1=(3 + 12)% 11 = 4, конфликт все еще существует, а затем найти следующий хеш-адрес — H2= (3 — 12) % 11 = 2 , в настоящее время конфликта нет, и впишите 69 в Блок 2.
-
Используйте псевдослучайное обнаружение и повторное хеширование для устранения коллизий: пусть псевдослучайная последовательность чисел будет: 2, 5, 9, …….., тогда следующий хэш-адрес будет H1=(3 + 2)% 11 = 5, все еще коллизия. Найдите следующий хеш-адрес как H2=(3 + 5)% 11 = 8. На данный момент конфликта нет, и заполните 69 в ячейке 8.
-
Перефразирование
Основная идея: при построении ряда различных хеш-функций:Hi=RH1(key) i=1, 2, ..., k
Когда хэш-адрес Hi=RH1(key) сталкивается, вычисляйте Hi=RH2(key)... до тех пор, пока конфликт не исчезнет. Этот подход менее склонен к кластеризации, но увеличивает время вычислений.
- метод цепного адреса
Основная идея: все записи с одинаковым хеш-адресом связаны в одном односвязном списке, а указатель на начало односвязного списка хранится в i-м элементе хеш-таблицы, поэтому в основном выполняются поиск, вставка и удаление. в цепочке синонимов.
Метод цепных адресов подходит для частых вставок и удалений.
- Создайте общую область переполнения
Основная идея: разделить хеш-таблицу на две части: основную и дополнительную, все элементы, конфликтующие с основной, будут помещены в дополнительную.
Java Threads.
Java-потоки
состояние потока
Есть в основном 5 состояний потока, а именно:新建,就绪,运行,阻塞,死亡.
- Новое состояние (Новое)
Когда создается пара объектов потока, она переходит в новое состояние, например:Thread t = new MyThread();
- Готовое состояние (Работает)
Когда вызывается метод start() объекта потока, поток переходит в состояние готовности. Поток в состоянии готовности означает только то, что поток готов и ожидает, пока ЦП запланирует выполнение в любое время, но не означает, что поток будет выполнен сразу после выполнения t.start(), например:t.start();
- Состояние работы (Выполняется)
Когда ЦП начинает планировать поток в состоянии готовности, поток фактически может выполняться в это время, то есть он переходит в состояние выполнения. Примечание. Состояние готовности — это единственный вход в состояние выполнения, то есть, если поток хочет войти в состояние выполнения для выполнения, он должен сначала находиться в состоянии готовности.
- Заблокированное состояние (заблокировано)
По какой-то причине поток в состоянии выполнения временно отказывается от права использования ЦП и прекращает выполнение.В это время он входит в состояние блокировки.Пока он не войдет в состояние готовности, он имеет возможность быть вызванным ЦП снова, чтобы войти в рабочее состояние. В зависимости от различных причин блокировки состояния блокировки можно разделить на три типа:
- ждать блокировки
Поток в состоянии выполнения выполняет метод wait(), чтобы перевести поток в состояние блокировки ожидания;
- синхронная блокировка
Если потоку не удается получить синхронизированную блокировку синхронизации (поскольку блокировка занята другими потоками), он переходит в состояние блокировки синхронизации;
- другая блокировка
Поток входит в состояние блокировки, вызывая sleep() или join() в потоке или отправляя запрос ввода-вывода. Когда время ожидания состояния sleep() истекает, join() ожидает, пока поток завершится или истечет время ожидания, или когда обработка ввода-вывода завершена, поток снова входит в состояние готовности.
- Мертвое состояние
Когда поток завершает выполнение или выходит из метода run() из-за исключения, поток завершает свой жизненный цикл.
жизненный цикл нити
Цикл объявления потока обычно начинается с нового состояния (New) и заканчивается мертвым состоянием (Dead), и в середине есть много возможностей.
Как показано на рисунке выше, обычно существует 4 ситуации ветвления:
-
нормальный (красная стрелка),
-
происходит блокировка блокировки (блокировка синхронизации) (синяя стрелка),
-
Корпус (желтая стрелка) ждать возникновения обструкции,
-
Другие блокировки происходят (черные стрелки), соответствующие направлениям потока 4 разных цветов в вышеуказанной фигуре
-
нормальная ситуация
Как показано красной стрелкой на рисунке выше, цикл объявления потока в нормальном состоянии выглядит следующим образом: NEW -> RUNNABLE -> RUNNING -> DEAD.
- Происходит блокировка блокировки (синхронная блокировка)
Как показано синей стрелкой на рисунке выше, когда поток переходит в состояние RUNNING и входит в блок синхронизированного метода, происходит блокировка блокировки, и поток входит в пул блокировок пула блокировки. Когда он получает блокировку, он снова входит в рабочее состояние. Когда осколок ЦП опрашивает его, он снова запускается до состояния DEAD.
- Ожидание блокировки
Как показано синей стрелкой на рисунке выше, когда поток встречает метод wait() при переходе в состояние RUNNING, возникает блок ожидания, и он будет ждать, пока другие потоки не вызовут метод notify(), чтобы освободить поток. блокировать перед возвратом в рабочее состояние. Когда осколок ЦП опрашивает его, он снова запускается до состояния DEAD. Ожидание блокировки и блокировка блокировки на самом деле являются одним и тем же типом, оба из которых являются ожиданием потока из-за конкуренции за блокировки.Единственная разница заключается в том, что они реализованы по-разному, но лежащие в их основе принципы одинаковы. Следует отметить, что при выполнении метода ожидания () поток должен получить блокировку, поэтому метод ожидания () обычно находится в синхронизированном методе или блоке кода. Когда он получает блокировку, он входит в пул ожидания и освобождает блокировку. После получения уведомления notify() подождите, пока будет получена блокировка, а затем он может запуститься после получения блокировки.
- Возникают другие блокировки (такие как: чтение ввода-вывода и т. д.)
Когда потоку необходимо прочитать файл, а файл занят другими потоками, произойдет блокировка. В это время поток должен дождаться завершения чтения другими потоками, прежде чем продолжить, что можно назвать блокировкой ввода-вывода. Конечно, есть много других ситуаций, таких как перегрузка сети и т. д.
Приложение CountDownLatch
CountDownLatch — это вспомогательный класс синхронизации, который позволяет потоку ждать, пока другие потоки завершат свою работу перед выполнением. Например, основной поток приложения может захотеть выполниться после того, как поток, отвечающий за запуск служб платформы, запустит все службы структуры.
Обзор реализации CountDownLatch
CountDownLatch реализуется счетчиком, начальным значением которого является количество потоков. Каждый раз, когда поток завершает свою задачу, значение счетчика уменьшается на 1. Когда значение счетчика достигает 0, это указывает на то, что все потоки завершили задачу, и тогда поток, ожидающий защелки, может возобновить выполнение задачи.
Многопоточное приложение CountDownLatch
Обход цикла списка (занимает 8697 мс)
@Test
public void optimizeListV1(){
long start = System.currentTimeMillis();
try {
final List<String> lists = Arrays.asList("aa", "bb", "cc", "dd", "ee");
for(int i=0; i<lists.size(); i++){
if(i == 2){
Thread.sleep(3000);
}
Thread.sleep(1000);
}
System.out.println("聚合完成");
}catch (Exception e){
}finally {
MockTimeUtil.mockInvokeTime("循环列表场景模拟:", start);
}
}
Многопоточный список агрегации (занимает 4671 мс)
@Test
public void optimizeList(){
long start = System.currentTimeMillis();
try {
ExecutorService ex = Executors.newFixedThreadPool(5);
final List<String> lists = Arrays.asList("aa", "bb", "cc", "dd", "ee");
final CountDownLatch latch = new CountDownLatch(lists.size());
for(int i=0; i<lists.size(); i++){
final int tmp = i;
ex.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
if(tmp == 2){
Thread.sleep(3000);
}
Thread.sleep(1000);
latch.countDown();
return null;
}
});
}
//latch.await();
latch.await(3500, TimeUnit.MILLISECONDS);
System.out.println("聚合完成");
}catch (Exception e){
}finally {
MockTimeUtil.mockInvokeTime("线程列表场景模拟:", start);
}
}
Описание метода CountDownLatch
Исходный код CountDownLatch
public class CountDownLatch {
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() {
sync.releaseShared(1);
}
public long getCount() {
return sync.getCount();
}
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
}
Описание метода:
- countDown(): когда текущий поток вызывает этот метод, счетчик уменьшается на единицу.
- await(): вызов этого метода заблокирует текущий поток, пока значение таймера не станет равным 0.
CompleteService Application
CompleteService использует сцены
Когда нам нужна пакетная обработка задач, но не важен порядок выполнения задач, мы отправляем задачи асинхронно, ждем завершения выполнения задачи, а затем обрабатываем результат выполнения, и так до тех пор, пока не будет выполнена пакетная задача. завершенный. Когда мы следуем принципу работы после завершения асинхронной обработки, кто первый завершит сбор урожая.
Обработка обхода на основе коллекции Future
Для этого сценария мы, вероятно, подумаем о том, чтобы собрать все асинхронные задачи в коллекцию, затем пройти по коллекции (Future), вызвать future.get() для получения результатов обработки и выполнить последующие операции, после чего мы напишем следующий код.
ExecutorService pool = Executors.newFixedThreadPool(5);
final List<String> dList = Arrays.asList("aa", "bb", "cc", "dd", "ee");
List<Future> fList= new ArrayList<Future>();
for(int i=0; i<dList.size(); i++){
final int tmp = i;
Future future = pool.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (tmp == 2) {
Thread.sleep(3000);
}
Thread.sleep(1000);
return "线程" + Thread.currentThread().getName() + "处理数据元素list(" + + tmp +") = " + dList.get(tmp) ;
}
});
fList.add(future);
}
System.out.println("聚合完成");
for (int i = 0; i < fList.size(); i++) {
System.out.println(fList.get(i).get());
}
Выполните этот код, вы обнаружите, что результат выполнения не такой, как мы ожидали.
聚合完成
线程pool-1-thread-1处理数据元素list(0) = aa
线程pool-1-thread-2处理数据元素list(1) = bb
线程pool-1-thread-3处理数据元素list(2) = cc
线程pool-1-thread-4处理数据元素list(3) = dd
线程pool-1-thread-5处理数据元素list(4) = ee
Видно, что приведенные выше результаты выполнения не то, что мы хотим.Очевидно, что выполнение cc элементов занимает много времени, но наши результаты обработки находятся в порядке обхода цикла.Причины следующие:
Каждый будущий объект, пройденный из списка, не обязательно в завершенном состоянии, и вызов метода GET () будет заблокирован. Если система будет разработана таким образом, чтобы каждый поток мог продолжать делать следующие вещи в соответствии с его результатами после завершения , Это добавляет дополнительное время ожидания потоков, которые за списком, но сначала закончите.
На основе полимеризации, проводимой параллельно CompletionService
ExecutorService pool = Executors.newFixedThreadPool(5);
CompletionService<Object> cs = new ExecutorCompletionService<Object>(pool);
final List<String> dList = Arrays.asList("aa", "bb", "cc", "dd", "ee");
for(int i=0; i<dList.size(); i++){
final int tmp = i;
cs.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (tmp == 2) {
Thread.sleep(3000);
}
Thread.sleep(1000);
return "线程" + Thread.currentThread().getName() + "处理数据元素list(" + + tmp +") = " + dList.get(tmp);
}
});
}
System.out.println("聚合完成");
for (int i = 0; i < dList.size(); i++) {
System.out.println(cs.take().get());
}
Выполнение обнаружит, что этот результат является тем, что мы действительно хотим
聚合
完成
线程pool-1-thread-2处理数据元素list(1) = bb
线程pool-1-thread-1处理数据元素list(0) = aa
线程pool-1-thread-4处理数据元素list(3) = dd
线程pool-1-thread-5处理数据元素list(4) = ee
线程pool-1-thread-3处理数据元素list(2) = cc
Мы можем получить желаемый результат, потому что BlockingQueue внутренне поддерживается в CompleteService.Принцип следующий:
Реализация CompletionService заключается в поддержке BlockingQueue, содержащей объекты Future. Только когда состояние объекта Future закончится, он будет добавлен в Очередь.Метод take() фактически является Потребителем в Производителе-Потребителе. Он возьмет объект Future из Очереди, и если Очередь пуста, он будет блокироваться там до тех пор, пока в Очередь не будет добавлен завершенный объект Future.
Разница между take() и poll() в CompleteService
Просмотр определения интерфейса CompleteService
public interface CompletionService<V> {
Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
Future<V> take() throws InterruptedException;
Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}
Из интерфейса видно, что связанные с саммитом методы, определенные в CompletionService, используются для загрузки тела потока (потоки обработки, которые реализуют Callable или Runable соответственно), а poll() и take() используются для получения возвращаемого результата. набор.
О разнице между poll() и take() of
poll() неблокирует.Если нет результата, он возвращает ноль, и поток продолжает работать без блокировки. take() блокируется, если нет текущего результата, поток блокируется до тех пор, пока не будет сгенерирован результат
Пример разницы между poll() и take()
ExecutorService pool = Executors.newFixedThreadPool(5);
CompletionService<Object> cs = new ExecutorCompletionService<Object>(pool);
final List<String> dList = Arrays.asList("aa", "bb", "cc", "dd", "ee");
for(int i=0; i<dList.size(); i++){
final int tmp = i;
cs.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (tmp == 2) {
Thread.sleep(3000);
}
Thread.sleep(1000);
return "线程" + Thread.currentThread().getName() + "处理数据元素list(" + + tmp +") = " + dList.get(tmp);
}
});
}
System.out.println("聚合完成");
AtomicInteger index = new AtomicInteger(0);
while(index.get()<dList.size()) {
Future<Object> f = cs.poll();
if(f == null) {
System.out.println("没发现有完成的任务");
}else {
System.out.println(f.get());
index.incrementAndGet();
}
Thread.sleep(500);
}
Результат работы программы
聚合完成
没发现有完成的任务
没发现有完成的任务
线程pool-1-thread-1处理数据元素list(0) = aa
线程pool-1-thread-4处理数据元素list(3) = dd
线程pool-1-thread-2处理数据元素list(1) = bb
线程pool-1-thread-5处理数据元素list(4) = ee
没发现有完成的任务
没发现有完成的任务
线程pool-1-thread-3处理数据元素list(2) = cc
Модель JavaIO
Модель JavaIO
При проектировании высокопроизводительной системы ввода-вывода есть несколько терминов и концепций, которые необходимо сначала обозначить.
Синхронные и асинхронные, блокирующие и неблокирующие
Синхронизация и асинхронность предназначены для взаимодействия между приложением и ядром.Блокировка и неблокировка-это разные способы, которые процесс принимает в соответствии с состоянием готовности операции ввода-вывода при доступе к данным.Грубо говоря, это своего рода чтения или записи В зависимости от того, как реализована функция операции ввода, в блокирующем режиме функция чтения или записи всегда будет ждать, в то время как в неблокирующем режиме функция чтения или записи немедленно вернет значение состояния. Короче говоря: синхронизация и асинхронность — это цель, блокировка и неблокировка — это путь.
- Синхронизация: относится к пользовательскому процессу, инициирующему операцию ввода-вывода и ожидающему или опрашивающему, чтобы узнать, готова ли операция ввода-вывода.
- Асинхронный: это означает, что пользовательский процесс начинает делать свое дело после запуска операции ввода-вывода, и когда операция ввода-вывода будет завершена, он будет уведомлен о завершении ввода-вывода (особенность асинхронности — уведомление), чтобы сообщить друзья размер, размер, цвет подходящей одежды, пусть друг поручает ее продать, а потом я могу сделать другие вещи сам.
- Блокировка: Так называемый метод блокировки означает, что при попытке чтения или записи дескриптора файла, если в это время нечего читать или он временно недоступен для записи, программа переходит в состояние ожидания, пока что-то не станет доступным для чтения или записи. пример: идём на автовокзал подзаряжаться, и обнаруживаем, что в это время зарядного устройства там нет (может сходили в туалет), то ждём здесь пока зарядное устройство не вернется.
- Неблокирующий: в неблокирующем состоянии, если нет ничего доступного для чтения или записи, функции чтения и записи вернутся немедленно, без ожидания.Например: при снятии денег в банке для ведения бизнеса мы получим небольшой билет, и мы можем играть сами после получения мобильного телефона или общаться с другими, когда придет наша очередь, динамик банка уведомит, тогда мы можем идти.
Модель ввода-вывода в Java
-
В Java есть три основные модели ввода-вывода: блокирующий ввод-вывод (BIO), неблокирующий ввод-вывод (NIO) и асинхронный ввод-вывод (AIO).
-
API, связанный с вводом-выводом, предоставленный в Java, фактически полагается на операцию ввода-вывода на уровне операционной системы при обработке файлов. Например, после Linux 2.6 и NIO, и AIO в Java реализуются через epoll, а в Windows AIO реализуется через IOCP.
Синхронный блокирующий ввод-вывод (JAVA BIO)
Синхронизация и блокировка, режим реализации сервера - одно соединение и один поток, то есть, когда у клиента есть запрос на соединение, серверу необходимо запустить поток для обработки.Если соединение ничего не делает, это вызовет ненужные накладные расходы потока .Конечно, это можно сделать через пул потоков.Механизм улучшен.
Синхронный неблокирующий ввод-вывод (Java NIO)
Синхронный и неблокирующий режим реализации сервера — один запрос на поток, то есть запрос на соединение, отправленный клиентом, будет зарегистрирован на мультиплексоре, и мультиплексор будет запускать поток только при опросе для соединения с вводом-выводом. просьба иметь дело с. Пользовательский процесс также должен время от времени спрашивать, готова ли операция ввода-вывода, что требует, чтобы пользовательский процесс продолжал спрашивать.
Асинхронный блокирующий ввод-вывод (Java NIO)
Таким образом, после того, как приложение инициирует операцию ввода-вывода, оно не ждет завершения операции ввода-вывода ядра.После того, как ядро завершит операцию ввода-вывода, приложение будет уведомлено.На самом деле это самое критическое различие между синхронизацией и асинхронностью. , Синхронизация должна ждать или активно спрашивать, завершен ли ввод-вывод, так почему он блокируется? Поскольку в настоящее время это делается с помощью системного вызова select, а реализация самой функции select блокируется, а использование функции select имеет то преимущество, что она может отслеживать несколько файловых дескрипторов одновременно (если с точки зрения UNP, выбор является синхронной операцией, потому что после выбора процесс также должен читать и записывать данные) для улучшения параллелизма системы!
Асинхронный неблокирующий ввод-вывод (Java AIO (NIO.2))
В этом режиме пользовательский процесс должен только инициировать операцию ввода-вывода, а затем немедленно вернуться.После того, как операция ввода-вывода действительно завершена, приложение будет уведомлено о завершении операции ввода-вывода.В это время пользовательскому процессу нужно только Обрабатывать данные.Никаких фактических операций чтения и записи ввода-вывода не требуется, потому что фактические операции чтения или записи ввода-вывода уже выполняются ядром.
Сценарии применения BIO, NIO, AIO
- Метод BIO подходит для структуры с относительно небольшим количеством соединений и фиксированным числом соединений.Этот метод имеет относительно высокие требования к ресурсам сервера, а параллелизм ограничен приложениями.Это единственный выбор до JDK1.4, но программа интуитивно понятна и проста в понимании.
- Метод NIO подходит для архитектур с большим количеством подключений и относительно короткими подключениями (легкая операция), таких как чат-серверы, где параллелизм ограничен приложениями, а программирование сложнее, JDK1.4 начал его поддерживать.
- Метод AIO используется для архитектур с большим количеством подключений и относительно длинным подключением (тяжелая операция), таких как сервер фотоальбомов, который полностью вызывает ОС для участия в параллельных операциях, а программирование более сложное. чтобы поддержать это.
Linux в модели IO
- В Linux (UNIX) существует пять моделей ввода-вывода: блокирующая модель ввода-вывода, неблокирующая модель ввода-вывода, управляемая сигналом модель ввода-вывода, модель мультиплексирования ввода-вывода и асинхронная модель ввода-вывода.
Блокирующая модель ввода-вывода
Блокирующий ввод-вывод — это простейшая модель ввода-вывода, которая обычно означает, что процесс или поток ожидает определенного условия, и если условие не выполняется, он ждет вечно. Если условия соблюдены, переходим к следующему шагу.
Процесс приложения получает данные с помощью системного вызова recvfrom, но поскольку ядро еще не подготовило дейтаграмму, процесс приложения будет заблокирован до тех пор, пока ядро не будет готово к приему дейтаграммы и recvfrom не завершит работу по копированию дейтаграммы, после чего процесс приложения может завершить работу. блокирующее состояние.
Неблокирующая модель ввода-вывода
Неблокирующая модель ввода-вывода. Процесс приложения взаимодействует с ядром, прежде чем цель будет достигнута, он больше не ждет вслепую, а возвращается напрямую. Затем с помощью опроса продолжайте спрашивать ядро, готовы ли данные. Если опрос обнаружит, что данные готовы, скопируйте данные в пространство пользователя.
Процесс приложения продолжает взаимодействовать с ядром через вызов recvfrom до тех пор, пока ядро не будет готово для данных. Если он не готов, ядро вернет ошибку, и процесс приложения отправит запрос recvfrom через некоторое время после получения ошибки. В течение времени между отправкой запроса процесс может сначала сделать что-то еще.
Модель ввода-вывода, управляемая сигналами
Процесс приложения уведомляет ядро при чтении файла, если на определенном сокете происходит определенное событие, пожалуйста, пришлите мне сигнал. После получения сигнала функция обработки, соответствующая сигналу, будет выполнять последующую обработку.
Процесс приложения заранее регистрирует функцию обработки сигнала в ядре, а затем пользовательский процесс возвращается без блокировки.Когда данные ядра будут готовы, он отправит сигнал процессу, и пользовательский процесс начнет копирование данных в пространство пользователя в функции обработки сигналов.
Модель повторного использования ввода-вывода
Ввод-вывод нескольких процессов может быть зарегистрирован в одном и том же канале, и этот канал будет единообразно взаимодействовать с ядром. Когда данные, необходимые для запроса в конвейере, готовы, процесс копирует соответствующие данные в пространство пользователя.
Мультиплексирование ввода-вывода - это дополнительная функция выбора, ввод-вывод нескольких процессов может быть зарегистрирован для одного и того же выбора, когда пользовательский процесс вызывает выбор, выбор будет контролировать все зарегистрированные операции ввода-вывода, если всем отслеживаемым операциям ввода-вывода нужны данные. Когда он не готов, выбор вызывающий процесс будет заблокирован. Когда данные, необходимые для любого IO, будут готовы, вызов select вернется, а затем процесс скопирует данные через recvfrom.
Модель мультиплексирования ввода-вывода здесь не регистрирует функции обработки сигналов в ядре, поэтому она не является неблокирующей. После того, как процесс выдает select, он не вернется, пока хотя бы одна из операций ввода-вывода, отслеживаемых select, не подготовит требуемые данные, и ему также необходимо снова отправить запрос для копирования файла.
Модель асинхронного ввода-вывода
Модель асинхронного ввода-вывода. После того, как процесс приложения передает запрос ввода-вывода ядру, ядро полностью отвечает за работу с копией файла. После того, как ядро завершит соответствующие операции, оно пошлет сигнал, чтобы сообщить процессу приложения, что ввод-вывод завершен.
После того, как пользовательский процесс инициирует операцию aio_read, он передает ядру дескриптор, указатель буфера, размер буфера и т. д., сообщая ядру, как уведомить процесс о завершении всей операции, а затем сразу же заняться другими делами. Когда ядро получает aio_read, оно немедленно возвращается, а затем ядро будет ждать подготовки данных.После того, как данные будут готовы, оно напрямую скопирует данные в пользовательский элемент управления, а затем уведомит процесс о том, что IO был было завершено.
Сравнение 5 моделей ввода-вывода
инструкция:
- Модель блокирующего ввода-вывода, неблокирующая модель ввода-вывода, модель мультиплексирования ввода-вывода и модель ввода-вывода, управляемая сигналом, являются синхронными моделями ввода-вывода. Причина в том, что независимо от вышеописанной модели реальный процесс копирования данных осуществляется синхронно.
- Несмотря на модель ввода-вывода сигнального драйвера, ядро уведомляется после того, как данные готовы, затем процесс используется для выполнения копирования данных с помощью операции RecVFrom. Можно подумать, что фаза подготовки данных асинхронна, но операция копирования данных синхронизирована. Поэтому весь процесс ввода-вывода нельзя считать асинхронным.
Ссылаться на
- Блог Woohoo.cn на.com/Forbidden City950516/Afraid…
- blog.CSDN.net/QQ_33098049…
- Блог Woo Woo.cn on.com/Wu Chao Electronic Information/…
- blog.CSDN.net/ также является локальной сетью/ ах…
- Блог Woohoo.cn на.com/QQ бесплатно 168/fear/3…
- Опыт Baidu.com/article/4 post 3…
- woo woo woo.cn blog on.com/moon geek/afraid/…
- у-у-у. Краткое описание.com/afraid/25 oh 243850…
- Tickets.WeChat.QQ.com/Yes/F VP B1R0 О 2…
- woo woo woo.cn blog on.com/Administrative Village/Fear/57…
- cmsblogs.com/?cat=183
- woo woo .cn блог на .com/ Кроме того, QQ и midi…
- ву ву .cn блог на.com/ignorant/Arch…