111. Tarmoqlar o'rtasida ma'lumotlar almashinuvi qanday amalga oshiriladi?
Tarmoqlar o'rtasida ma'lumot almashish uchun siz turli xil yondashuvlar va vositalardan foydalanishingiz mumkin: masalan, atom o'zgaruvchilari, sinxronlashtirilgan to'plamlar va semafordan foydalaning. Ammo bu muammoni hal qilish uchun men Exchanger bilan misol keltiraman . Exchanger - bu umumiy sinxronizatsiya nuqtasini yaratish orqali bir juft ip o'rtasida elementlar almashinuvini osonlashtiradigan bir vaqtning o'zida to'plamdagi sinxronizatsiya sinfidir . Uning ishlatilishi ikki ip o'rtasida ma'lumotlar almashinuvini soddalashtiradi. Uning ishlash usuli juda oddiy: u exchange() usulini chaqirish uchun ikkita alohida ish zarrachasini kutadi . Ular orasida almashinuv nuqtasiga o'xshash narsa yaratiladi: birinchi ip o'z ob'ektini qo'yadi va buning evaziga ikkinchisining ob'ektini oladi, ikkinchisi esa, o'z navbatida, birinchisining ob'ektini oladi va o'zinikini qo'yadi. Ya'ni, birinchi ish zarrachasi exchange() usulidan foydalanadi va bir xil ob'ektdagi exchange() usulini boshqa ip chaqirmaguncha va ular o'rtasida ma'lumotlar almashguncha bo'sh qoladi . Misol sifatida, Thread sinfining quyidagi amalga oshirilishini ko'rib chiqing :public class CustomThread extends Thread {
private String threadName;
private String message;
private Exchanger<String> exchanger;
public CustomThread(String threadName, Exchanger<String> exchanger) {
this.threadName = threadName;
this.exchanger = exchanger;
}
public void setMessage(final String message) {
this.message = message;
}
@Override
public void run() {
while (true) {
try {
message = exchanger.exchange(message);
System.out.println(threadName + " поток получил сообщение: " + message);
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Tarmoq konstruktorida biz String tipidagi ob'ektlarni qabul qiladigan Exchanger ob'ektini aniqlaymiz va ishga tushirilganda (ishlash usulida ) biz o'sha Exchangerda ushbu usuldan foydalanadigan boshqa oqim bilan xabar almashish uchun uning exchange() dan foydalanamiz . Keling, uni asosiyda ishga tushiramiz :
Exchanger<String> exchanger = new Exchanger<>();
CustomThread first = new CustomThread("Первый ", exchanger);
first.setMessage("Сообщение первого потока");
CustomThread second = new CustomThread("Второй", exchanger);
second.setMessage("Сообщение второго потока");
first.start();
second.start();
Konsolda ko'rsatiladi:
112. Thread sinfi va Runnable interfeysi o'rtasidagi farq nima?
Men e'tiborga oladigan birinchi narsa - bu Thread - bu sinf, Runnable - bu interfeys, bu juda aniq farq =D Men shuni ham aytamanki, Thread Runnable (kompozitsiya) dan foydalanadi . Ya'ni, bizda ikkita yo'l bor:-
Thread dan meros qilib oling , ishga tushirish usulini bekor qiling, so'ngra ushbu ob'ektni yarating va start() usuli orqali ipni boshlang .
-
Runnable-ni ma'lum bir sinfda amalga oshiring , uning run() usulini qo'llang va keyin Thread ob'ektini yarating, Runnable interfeysining ushbu ob'ektini konstruktoriga tayinlang . Oxirida start() usuli yordamida Thread obyektini ishga tushiring .
-
Runnable interfeysini amalga oshirganingizda , siz ipning harakatini o'zgartirmaysiz. Asosan, siz shunchaki ipni ishga tushirish uchun biror narsa berasiz. Va bu bizning kompozitsiyamiz, bu o'z navbatida yaxshi yondashuv hisoblanadi.
-
Runnable dasturini amalga oshirish sizning sinfingizga ko'proq moslashuvchanlikni beradi. Agar siz Thread dan meros bo'lsangiz , bajarayotgan amal har doim ipda bo'ladi. Agar siz Runnable dasturini amalga oshirsangiz , u shunchaki ip bo'lishi shart emas. Axir, siz uni ish zarrachasida ishga tushirishingiz yoki ba'zi bir ijrochi xizmatiga topshirishingiz mumkin. Xo'sh, yoki shunchaki bitta tarmoqli ilovada vazifa sifatida uni biron joyga o'tkazing.
-
Runnable- dan foydalanish sizga vazifani bajarishni ipni boshqarish mantig'idan mantiqiy ajratish imkonini beradi.
-
Java-da faqat bitta meros mumkin, shuning uchun faqat bitta sinfni kengaytirish mumkin. Shu bilan birga, kengaytiriladigan interfeyslar soni cheksizdir (yaxshi, cheksiz emas, lekin 65535 , lekin siz bu chegaraga hech qachon erisha olmaysiz).
113. T1, T2 va T3 iplari mavjud. Qanday qilib ularni ketma-ket amalga oshirish kerak?
Aqlga keladigan birinchi va eng oddiy narsa bu join() usulidan foydalanishdir . U joriy ish zarrachasining (usul deb ataladigan) bajarilishini, usul deb atalgan ip bajarilishini tugatmaguncha to'xtatib turadi. Keling, o'z ish zarrachamizni yarataylik:public class CustomThread extends Thread {
private String threadName;
public CustomThread(final String threadName){
this.threadName = threadName;
}
@Override
public void run() {
System.out.println(threadName + " - начал свою работу");
try {
// происходит некая логика
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + " - закончил свою работу");
}
}
Keling, join() yordamida uchta shunday mavzuni birma-bir boshlaylik :
CustomThread t1 = new CustomThread("Первый поток");
t1.start();
t1.join();
CustomThread t2 = new CustomThread("Второй поток");
t2.start();
t2.join();
CustomThread t3 = new CustomThread("Третий поток");
t3.start();
t3.join();
Konsol chiqishi:
Amaliy topshiriqlar
114. Matritsaning diagonal yig‘indisi (Leetcode muammosi)
Shart: Asosiy diagonalning barcha elementlari va qo'shimcha diagonalning asosiy diagonalning bir qismi bo'lmagan barcha elementlari yig'indisini hisoblang. 1. Ko'rinishdagi matritsa bilan: mat = [[1,2,3], [4,5,6], [7,8,9]] Chiqish - 25 bo'lishi kerak 2. Matritsa bilan - mat = [[1,1 ,1,1], [1,1,1,1], [1,1,1,1], [1,1,1,1]] Chiqish - 8 3 bo'lishi kerak. a matritsa - mat = [[ 5]] Xulosa bo'lishi kerak - 5 O'qishni to'xtatib turing va qaroringizni amalga oshiring. Mening yechimim quyidagicha bo'ladi:public static int countDiagonalSum(int[][] matrix) {
int sum = 0;
for (int i = 0, j = matrix.length - 1; i < matrix.length; i++, j--) {
sum += matrix[i][i];
if (j != i) {
sum += matrix[i][j];
}
}
return sum;
}
Hamma narsa massivdan bir marta o'tish bilan sodir bo'ladi, bunda bizda hisobot uchun ikkita indeks mavjud: i - massiv qatorlari va asosiy diagonal ustunlari haqida xabar berish uchun, j - qo'shimcha diagonal ustunlari haqida xabar berish uchun. Agar asosiy diagonal va qo'shimcha katakcha mos kelsa, yig'indini hisoblashda qiymatlardan biri e'tiborga olinmaydi. Shartdagi matritsalar yordamida tekshiramiz:
int[][] arr1 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
System.out.println(countDiagonalSum(arr1));
int[][] arr2 = {
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}};
System.out.println(countDiagonalSum(arr2));
int[][] arr3 = {{5}};
System.out.println(countDiagonalSum(arr3));
Konsol chiqishi:
115. Nollarni siljitish (Leetcode challenge)
Shart: Butun sonli massivda nolga teng bo'lmagan elementlarning nisbiy tartibini saqlab, barcha 0 larni oxirigacha ko'chiring. 1. Massiv bilan: [0,1,0,3,12] Chiqish quyidagicha bo'lishi kerak: [1,3,12,0,0] 2. Massiv bilan: [0] Chiqish quyidagicha bo'lishi kerak: [0] To'xtab, qarorimni yozing... Mening qarorim:public static void moveZeroes(int[] nums) {
int counterWithoutNulls = 0;
int counterWithNulls = 0;
int length = nums.length;
while (counterWithNulls < length) {
if (nums[counterWithNulls] == 0) {// находим нулевые элементы и увеличиваем счётчик
counterWithNulls++;
} else { // сдвигаем элементы на количество найденных нулевых элементов слева
nums[counterWithoutNulls++] = nums[counterWithNulls++];
}
}
while (counterWithoutNulls < length) {
nums[counterWithoutNulls++] = 0;// заполняем последние элементы массива нулями согласно счётчику нулей
}
}
Imtihon:
int[] arr1 = {1, 2, 0, 0, 12, 9};
moveZeroes(arr1);
System.out.println(Arrays.toString(arr1));
int[] arr2 = {0};
moveZeroes(arr2);
System.out.println(Arrays.toString(arr2));
Konsol chiqishi:
116. Berilgan ro'yxat <String> nomlari. Har bir nomdan birinchi harfni olib tashlang va tartiblangan ro'yxatni aylantiring
1. Aqlga keladigan birinchi narsa bu Collections sinfining usullari bo'lib , unda to'plamlar uchun ko'plab yordamchi usullar mavjud:public static List<String> processTheList(List<String> nameList) {
for (int i = 0; i < nameList.size(); i++) {
nameList.set(i, nameList.get(i).substring(1));
}
Collections.sort(nameList);
return nameList;
}
2. Bundan tashqari, agar biz Java 8 va undan yuqori versiyalaridan foydalansak, yechimni oqimlar orqali ko‘rsatishimiz kifoya:
public static List<String> processTheList(List<String> nameList) {
return nameList.stream()
.map(x -> x.substring(1))
.sorted().collect(Collectors.toList());
}
Tanlangan yechimdan qat'i nazar, tekshirish quyidagicha bo'lishi mumkin:
List<String> nameList = new ArrayList();
nameList.add("John");
nameList.add("Bob");
nameList.add("Anna");
nameList.add("Dmitriy");
nameList.add("Peter");
nameList.add("David");
nameList.add("Igor");
System.out.println(processTheList(nameList));
Konsol chiqishi:
117. Massivni aylantiring
Yechim 1 Shunga qaramay, aqlga kelgan birinchi narsa yordamchi yordamchi sinfning usullaridan foydalanishdir Collections . Ammo bizda massiv bor ekan, avval uni to'plamga (ro'yxat) aylantirishimiz kerak:public static Integer[] reverse(Integer[] arr) {
List<Integer> list = Arrays.asList(arr);
Collections.reverse(list);
return list.toArray(arr);
}
2-echim Savol massiv haqida bo'lganligi sababli, menimcha, tayyor funksionallikni qutidan tashqarida ishlatmasdan va klassikaga ko'ra, yechimni ko'rsatish kerak:
public static Integer[] reverse(Integer[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
return arr;
}
Imtihon:
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.println(Arrays.toString(reverse(arr)));
Konsol chiqishi:
118. Satrning palindrom ekanligini tekshiring
1-yechim StringBuilder- ni zudlik bilan esga olish kerak : u oddiy String bilan solishtirganda ancha moslashuvchan va turli usullarga boy . Bizni ayniqsa teskari usul qiziqtiradi :public static boolean isPalindrome(String string) {
string = string.toLowerCase(); //приводит всю строку к нижнему регистру
StringBuilder builder = new StringBuilder();
builder.append(string);
builder.reverse(); // перевочиваем строку методом Builder-а
return (builder.toString()).equals(string);
}
Yechim: Keyingi yondashuv qutidagi "bo'shliqlar" dan foydalanmasdan bo'ladi. Biz satrning orqa qismidagi belgilarni old tomondan tegishli belgilar bilan taqqoslaymiz:
public static boolean isPalindrome(String string) {
string = string.toLowerCase();
int length = string.length();
int fromBeginning = 0;
int fromEnd = length - 1;
while (fromEnd > fromBeginning) {
char forwardChar = string.charAt(fromBeginning++);
char backwardChar = string.charAt(fromEnd--);
if (forwardChar != backwardChar)
return false;
}
return true;
}
Va ikkala yondashuvni ham tekshiramiz:
boolean isPalindrome = isPalindrome("Tenet");
System.out.println(isPalindrome);
Konsol chiqishi:
119. Oddiy tartiblash algoritmini yozing (Bubble, Selection yoki Shuttle). Uni qanday yaxshilash mumkin?
Amalga oshirish uchun oddiy algoritm sifatida men tanlovni saralashni tanladim - Tanlovni saralash:public static void selectionSorting(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int min = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]) {
min = j; // выбираем минимальный элемент в текущем числовом отрезке
}
}
int temp = arr[min]; // меняем местами минимальный элемент с элементом под индексом i
arr[min] = arr[i]; // так How отрезок постоянно уменьшается
arr[i] = temp; // и выпадающие из него числа будут минимальными в текущем отрезке
} // и How итог - числа оставшиеся вне текущей итерации отсортированы от самого наименьшего к большему
}
Yaxshilangan versiya quyidagicha ko'rinadi:
public static void improvedSelectionSorting(int[] arr) {
for (int i = 0, j = arr.length - 1; i < j; i++, j--) { // рассматриваемый отрезок с каждой итерацией
// будет уменьшаться с ДВУХ сторон по одному элементу
int min = arr[i];
int max = arr[i];
int minIndex = i;
int maxIndex = i;
for (int n = i; n <= j; n++) { // выбираем min и max на текущем отрезке
if (arr[n] > max) {
max = arr[n];
maxIndex = n;
} else if (arr[n] < min) {
min = arr[n];
minIndex = n;
}
}
// меняем найденный минимальный элемент с позиции с индексом min на позицию с индексом i
swap(arr, i, minIndex);
if (arr[minIndex] == max) {// срабатывает, если элемент max оказался смещен предыдущей перестановкой -
swap(arr, j, minIndex); // на старое место min, поэтому с позиции с индексом min смещаем его на позицию j
} else {
swap(arr, j, maxIndex); // простое обмен местами элементов с индексами max и j
}
}
}
static int[] swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
Xo'sh, endi saralash haqiqatan ham yaxshilanganiga ishonch hosil qilishimiz kerak. Keling, samaradorlikni taqqoslaylik:
long firstDifference = 0;
long secondDifference = 0;
long primaryTime;
int countOfApplying = 10000;
for (int i = 0; i < countOfApplying; i++) {
int[] arr1 = {234, 33, 123, 4, 5342, 76, 3, 65,
3, 5, 35, 75, 255, 4, 46, 48, 4658, 44, 22,
678, 324, 66, 151, 268, 433, 76, 372, 45, 13,
9484, 499959, 567, 774, 473, 3, 32, 865, 67, 43,
63, 332, 24, 1};
primaryTime = System.nanoTime();
selectionSorting(arr1);
firstDifference += System.nanoTime() - primaryTime;
int[] arr2 = {234, 33, 123, 4, 5342, 76, 3, 65,
3, 5, 35, 75, 255, 4, 46, 48, 4658, 44, 22,
678, 324, 66, 151, 268, 433, 76, 372, 45, 13,
9484, 499959, 567, 774, 473, 3, 32, 865, 67, 43,
63, 332, 24, 1};
primaryTime = System.nanoTime();
improvedSelectionSorting(arr2);
secondDifference += System.nanoTime() - primaryTime;
}
System.out.println(((double) firstDifference / (double) secondDifference - 1) * 100 + "%");
Ikkala tur ham bir xil tsiklda boshlangan, chunki agar alohida looplar bo'lsa, yuqoridagi koddan saralash ikkinchi o'ringa qo'yilgandan ko'ra yomonroq natijalarni ko'rsatadi. Buning sababi dasturning "isishi" va keyin biroz tezroq ishlashidir. Lekin men mavzudan biroz chetga chiqyapman. Konsolda ushbu tekshiruvni besh marta o'tkazgandan so'ng, men ishlashning o'sishini ko'rdim: 36,41006735635892% 51,46131097160771% 41,88918834013988% 48,09198070574370162 , men uchun bu 32214%. juda yaxshi natija.
120. Int tipidagi literalni bayt tipidagi literal bilan tuzish algoritmini (harakatlar ketma-ketligini) yozing. Xotira bilan nima sodir bo'lishini tushuntiring
-
bayt qiymati int ga aylantiriladi. Buning uchun 1 bayt xotira ajratilmaydi, lekin barcha int qiymatlari kabi - 4, agar bu qiymat hali int stekida bo'lmasa. Agar mavjud bo'lsa, unga havola shunchaki olinadi.
-
Ikkita int qiymati qo'shiladi va uchinchisi olinadi. Buning uchun yangi xotira bo'limi ajratiladi - 4 bayt (yoki int stekidan mavjud qiymatga havola olinadi).
Bunday holda, ikkita int xotirasi hali ham band bo'ladi va ularning qiymatlari mos ravishda int stekida saqlanadi.
GO TO FULL VERSION