---
# System prepended metadata

title: lab 2 java

---

lab 2 java
=======

Main.java
```java
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Stack stack = new Stack();

        Thread producer1 = new Thread(new LatinLetterProducer(stack));
        Thread producer2 = new Thread(new LatinLetterProducer(stack));
        Thread killer1 = new Thread(new KillerSymbolProducer(stack));
        Thread killer2 = new Thread(new KillerSymbolProducer(stack));

        producer1.start();
        producer2.start();
        killer1.start();
        killer2.start();
    }
}

class LatinLetterProducer implements Runnable {
    private Stack stack;
    private Random random = new Random();

    public LatinLetterProducer(Stack stack) {
        this.stack = stack;
    }

    @Override
    public void run() {
        while (true) {
            int count = random.nextInt(4) + 2; // Произвести от 2 до 5 символов
            for (int i = 0; i < count; i++) {
                char letter = (char) (random.nextInt(26) + 'a'); // Случайная латинская строчная буква
                try {
                    stack.push(letter);
                    // System.out.println(Thread.currentThread().getName() + " produced " + letter);
                    // stack.printStack();
                    Thread.sleep(random.nextInt(1000)); // Случайная задержка перед следующим символом
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class KillerSymbolProducer implements Runnable {
    private Stack stack;
    private Random random = new Random();

    public KillerSymbolProducer(Stack stack) {
        this.stack = stack;
    }

    @Override
    public void run() {
        while (true) {
            int count = random.nextInt(2) + 1; // Произвести 1 или 2 символа-убийцы
            for (int i = 0; i < count; i++) {
                char killerSymbol = random.nextBoolean() ? '#' : '@'; // Случайный символ-убийца
                try {
                    if (killerSymbol == '#') {
                        stack.pop();
                        // System.out.println(Thread.currentThread().getName() + " produced " + killerSymbol + " and removed one symbol");
                    } else {
                        stack.pop2();
                        // System.out.println(Thread.currentThread().getName() + " produced " + killerSymbol + " and removed two symbols");
                    }
                    // stack.printStack();
                    Thread.sleep(random.nextInt(1500)); // Случайная задержка перед следующим символом
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

```
Stack.java
```java
import java.util.concurrent.locks.*;

public class Stack {
    private char[] stack;
    private int top = -1;
    private static final int CAPACITY = 15;
    private ReentrantLock lock = new ReentrantLock();
    private Condition stackFullCondition = lock.newCondition();
    private Condition stackEmptyCondition = lock.newCondition();

    public Stack() {
        stack = new char[CAPACITY];
    }

    public void push(char item) throws InterruptedException {
        lock.lock();
        try {
            while (isFull()) {
                stackFullCondition.await();
            }
            top++;
            stack[top] = item;
            System.out.print(Thread.currentThread().getName() + " push( "+ item + " ) ");
            printStack();
            stackEmptyCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public char pop() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty()) {
                stackEmptyCondition.await();
            }
            char item = stack[top];
            top--;
            System.out.print(Thread.currentThread().getName() + " pop() "+ item + "   ");
            printStack();
            stackFullCondition.signalAll();
            return item;
        } finally {
            lock.unlock();
        }
    }

    public String pop2() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty() || top < 1) {
                stackEmptyCondition.await();
            }
            char item1 = stack[top];
            top--;
            char item2 = stack[top];
            top--;
            System.out.print(Thread.currentThread().getName() + " pop2()"+ item1 + item2 + "  ");
            printStack();
            stackFullCondition.signalAll();
            return "" + item1 + item2;
        } finally {
            lock.unlock();
        }
    }

    public char top() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty()) {
                stackEmptyCondition.await();
            }
            return stack[top];
        } finally {
            lock.unlock();
        }
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == CAPACITY - 1;
    }

    public void printStack() {
        lock.lock();
        try {
            if (isEmpty()) {
                System.out.println("Stack is empty.");
            } else {
                System.out.print("Stack: ");
                for (int i = 0; i <= top; i++) {
                    System.out.print(stack[i] + " ");
                }
                System.out.println();
            }
        } finally {
            lock.unlock();
        }
    }
}
```

Пример работы
```
> javac *.java ; java Main
Thread-0 push( g ) Stack: g 
Thread-1 push( u ) Stack: g u 
Thread-2 pop() u   Stack: g 
Thread-1 push( d ) Stack: g d 
Thread-3 pop2()dg  Stack is empty.
Thread-0 push( t ) Stack: t 
Thread-2 pop() t   Stack is empty.
Thread-0 push( e ) Stack: e 
Thread-3 pop() e   Stack is empty.
Thread-1 push( w ) Stack: w 
Thread-2 pop() w   Stack is empty.
Thread-0 push( r ) Stack: r 
Thread-1 push( o ) Stack: r o 
Thread-3 pop() o   Stack: r 
Thread-0 push( n ) Stack: r n 
Thread-0 push( j ) Stack: r n j 
Thread-2 pop2()jn  Stack: r 
Thread-0 push( y ) Stack: r y 
Thread-2 pop2()yr  Stack is empty.
Thread-0 push( f ) Stack: f 
Thread-1 push( o ) Stack: f o 
Thread-3 pop2()of  Stack is empty.
Thread-0 push( a ) Stack: a 
Thread-1 push( s ) Stack: a s 
Thread-1 push( i ) Stack: a s i 
Thread-2 pop2()is  Stack: a 
Thread-0 push( s ) Stack: a s 
Thread-3 pop2()sa  Stack is empty.
Thread-0 push( t ) Stack: t 
Thread-1 push( y ) Stack: t y 
Thread-0 push( w ) Stack: t y w 
Thread-1 push( i ) Stack: t y w i 
Thread-1 push( k ) Stack: t y w i k 
Thread-1 push( x ) Stack: t y w i k x 
Thread-1 push( z ) Stack: t y w i k x z 
Thread-3 pop() z   Stack: t y w i k x 
Thread-2 pop() x   Stack: t y w i k 
Thread-1 push( d ) Stack: t y w i k d 
Thread-0 push( f ) Stack: t y w i k d f 
Thread-2 pop() f   Stack: t y w i k d 
Thread-0 push( r ) Stack: t y w i k d r 
Thread-1 push( j ) Stack: t y w i k d r j 
Thread-3 pop2()jr  Stack: t y w i k d 
Thread-2 pop2()dk  Stack: t y w i 
Thread-1 push( u ) Stack: t y w i u 
Thread-3 pop() u   Stack: t y w i 
Thread-0 push( g ) Stack: t y w i g 
Thread-2 pop2()gi  Stack: t y w 
Thread-1 push( r ) Stack: t y w r 
Thread-1 push( r ) Stack: t y w r r 
Thread-3 pop2()rr  Stack: t y w 
Thread-0 push( d ) Stack: t y w d 
Thread-1 push( b ) Stack: t y w d b 
Thread-1 push( a ) Stack: t y w d b a 
Thread-0 push( c ) Stack: t y w d b a c 
Thread-2 pop2()ca  Stack: t y w d b 
Thread-0 push( c ) Stack: t y w d b c 
Thread-3 pop2()cb  Stack: t y w d 
Thread-1 push( t ) Stack: t y w d t 
Thread-3 pop() t   Stack: t y w d 
Thread-0 push( m ) Stack: t y w d m 
Thread-3 pop() m   Stack: t y w d 
Thread-0 push( i ) Stack: t y w d i 
Thread-2 pop() i   Stack: t y w d 
Thread-3 pop2()dw  Stack: t y 
Thread-1 push( t ) Stack: t y t 
Thread-3 pop() t   Stack: t y 
Thread-0 push( r ) Stack: t y r 
Thread-2 pop2()ry  Stack: t 
Thread-0 push( e ) Stack: t e 
Thread-1 push( s ) Stack: t e s 
Thread-0 push( i ) Stack: t e s i 
Thread-3 pop2()is  Stack: t e 
Thread-1 push( z ) Stack: t e z 
Thread-0 push( f ) Stack: t e z f 
Thread-1 push( g ) Stack: t e z f g 
Thread-3 pop() g   Stack: t e z f 
Thread-0 push( o ) Stack: t e z f o 
Thread-2 pop() o   Stack: t e z f 
Thread-0 push( z ) Stack: t e z f z 
Thread-0 push( c ) Stack: t e z f z c 
Thread-1 push( j ) Stack: t e z f z c j 
Thread-3 pop2()jc  Stack: t e z f z 
Thread-0 push( e ) Stack: t e z f z e 
Thread-1 push( l ) Stack: t e z f z e l 
Thread-1 push( m ) Stack: t e z f z e l m 
Thread-0 push( u ) Stack: t e z f z e l m u 
Thread-3 pop2()um  Stack: t e z f z e l 
Thread-2 pop() l   Stack: t e z f z e 
Thread-0 push( i ) Stack: t e z f z e i 
Thread-1 push( z ) Stack: t e z f z e i z 
Thread-0 push( d ) Stack: t e z f z e i z d 
Thread-0 push( n ) Stack: t e z f z e i z d n 
Thread-3 pop2()nd  Stack: t e z f z e i z 
Thread-2 pop() z   Stack: t e z f z e i 
Thread-1 push( g ) Stack: t e z f z e i g 
Thread-0 push( y ) Stack: t e z f z e i g y 
Thread-2 pop() y   Stack: t e z f z e i g 
Thread-3 pop() g   Stack: t e z f z e i 
```


# Проект 🤡

Класс `Main`:
```
1. Создать экземпляр класса Stack.
2. Создать и запустить два потока LatinLetterProducer для производства случайных латинских строчных букв.
3. Создать и запустить два потока KillerSymbolProducer для производства символов-убийц.
```

Класс `LatinLetterProducer`:
```
1. Получить ссылку на объект Stack в конструкторе.
2. В методе run():
   - Бесконечно выполнять следующие шаги:
     a. Сгенерировать случайное число count от 2 до 5 (количество символов для производства).
     b. Повторить count раз:
        i. Сгенерировать случайную латинскую строчную букву.
        ii. Поместить сгенерированную букву в стек, используя метод push().
        iii. Вывести информацию о произведенной букве и текущем содержимом стека.
        iv. Сделать случайную задержку перед генерацией следующей буквы.
```

Класс `KillerSymbolProducer`:
```
1. Получить ссылку на объект Stack в конструкторе.
2. В методе run():
   - Бесконечно выполнять следующие шаги:
     a. Сгенерировать случайное число count (1 или 2) для определения количества символов-убийц.
     b. Повторить count раз:
        i. Сгенерировать случайный символ-убийцу ('#' или '@').
        ii. Если сгенерированный символ - '#':
           - Удалить один символ из стека, используя метод pop().
           - Вывести информацию об удаленном символе и текущем содержимом стека.
        iii. Если сгенерированный символ - '@':
            - Удалить два символа из стека, используя метод pop2().
            - Вывести информацию об удаленных символах и текущем содержимом стека.
        iv. Сделать случайную задержку перед генерацией следующего символа-убийцы.
```

Класс `Stack`:
```
1. Инициализировать массив stack фиксированного размера CAPACITY для хранения символов.
2. Инициализировать указатель top в -1 (индекс верхнего элемента стека).
3. Создать объект блокировки lock для обеспечения потокобезопасности.
4. Создать условия stackFullCondition и stackEmptyCondition для координации потоков.

Метод push(char item):
1. Получить блокировку lock.
2. Пока стек полон, ждать на условии stackFullCondition.
3. Увеличить указатель top на 1.
4. Поместить символ item в массив stack по индексу top.
5. Сигнализировать всем потокам, ожидающим на условии stackEmptyCondition.
6. Освободить блокировку lock.

Метод pop():
1. Получить блокировку lock.
2. Пока стек пуст, ждать на условии stackEmptyCondition.
3. Получить символ из массива stack по индексу top и сохранить его в переменной item.
4. Уменьшить указатель top на 1.
5. Сигнализировать всем потокам, ожидающим на условии stackFullCondition.
6. Освободить блокировку lock.
7. Вернуть символ item.

Метод pop2():
1. Получить блокировку lock.
2. Пока стек пуст или содержит менее двух элементов, ждать на условии stackEmptyCondition.
3. Получить два символа из массива stack по индексам top и top-1 и сохранить их в переменных item1 и item2.
4. Уменьшить указатель top на 2.
5. Сигнализировать всем потокам, ожидающим на условии stackFullCondition.
6. Освободить блокировку lock.
7. Вернуть строку, состоящую из item1 и item2.

Метод printStack():
1. Получить блокировку lock.
2. Если стек пуст, вывести сообщение "Stack is empty".
3. Иначе, вывести содержимое стека, начиная с индекса 0 до top.
4. Освободить блокировку lock.
```

Эти словесные "проекты" описывают алгоритмы и логику работы каждого класса и его методов. Они помогают понять последовательность действий и взаимодействие между классами и потоками в программе.

# Проект 2 🤡
обновленные словесные "проекты" с учетом доступов, объявлений переменных и классов:

Класс `Main`:
```java
public class Main {
    public static void main(String[] args) {
        1. Создать экземпляр класса Stack.
        2. Создать и запустить два потока LatinLetterProducer для производства случайных латинских строчных букв.
        3. Создать и запустить два потока KillerSymbolProducer для производства символов-убийц.
    }
}
```

Класс `LatinLetterProducer`:
```java
class LatinLetterProducer implements Runnable {
    private Stack stack;
    private Random random = new Random();

    public LatinLetterProducer(Stack stack) {
        1. Получить ссылку на объект Stack в конструкторе.
    }

    @Override
    public void run() {
        1. Бесконечно выполнять следующие шаги:
           a. Сгенерировать случайное число count от 2 до 5 (количество символов для производства).
           b. Повторить count раз:
              i. Сгенерировать случайную латинскую строчную букву.
              ii. Поместить сгенерированную букву в стек, используя метод push().
              iii. Вывести информацию о произведенной букве и текущем содержимом стека.
              iv. Сделать случайную задержку перед генерацией следующей буквы.
    }
}
```

Класс `KillerSymbolProducer`:
```java
class KillerSymbolProducer implements Runnable {
    private Stack stack;
    private Random random = new Random();

    public KillerSymbolProducer(Stack stack) {
        1. Получить ссылку на объект Stack в конструкторе.
    }

    @Override
    public void run() {
        1. Бесконечно выполнять следующие шаги:
           a. Сгенерировать случайное число count (1 или 2) для определения количества символов-убийц.
           b. Повторить count раз:
              i. Сгенерировать случайный символ-убийцу ('#' или '@').
              ii. Если сгенерированный символ - '#':
                 - Удалить один символ из стека, используя метод pop().
                 - Вывести информацию об удаленном символе и текущем содержимом стека.
              iii. Если сгенерированный символ - '@':
                  - Удалить два символа из стека, используя метод pop2().
                  - Вывести информацию об удаленных символах и текущем содержимом стека.
              iv. Сделать случайную задержку перед генерацией следующего символа-убийцы.
    }
}
```

Класс `Stack`:
```java
public class Stack {
    private char[] stack; // массив для хранения символов.
    private int top = -1; // указатель на верхний элемент стека.
    private static final int CAPACITY = 10; // емкость стека.
    private ReentrantLock lock = new ReentrantLock(); // объект блокировки для обеспечения потокобезопасности.
    private Condition stackFullCondition = lock.newCondition(); // условие для ожидания, когда стек полон.
    private Condition stackEmptyCondition = lock.newCondition(); // условие для ожидания, когда стек пуст.

    public Stack() {
        1. Инициализировать массив stack фиксированного размера CAPACITY для хранения символов.
    }

    public void push(char item) throws InterruptedException {
        1. Получить блокировку lock.
        2. Пока стек полон, ждать на условии stackFullCondition.
        3. Увеличить указатель top на 1.
        4. Поместить символ item в массив stack по индексу top.
        5. Вывести информацию о потоке методе и состоянии стека
        6. Сигнализировать всем потокам, ожидающим на условии stackEmptyCondition.
        7. Освободить блокировку lock.
    }

    public char pop() throws InterruptedException {
        1. Получить блокировку lock.
        2. Пока стек пуст, ждать на условии stackEmptyCondition.
        3. Получить символ из массива stack по индексу top и сохранить его в переменной item.
        4. Уменьшить указатель top на 1.
        6. Вывести информацию о потоке методе и состоянии стека
        7. Сигнализировать всем потокам, ожидающим на условии stackFullCondition.
        8. Освободить блокировку lock.
        9. Вернуть символ item.
    }

    public String pop2() throws InterruptedException {
        1. Получить блокировку lock.
        2. Пока стек пуст или содержит менее двух элементов, ждать на условии stackEmptyCondition.
        3. Получить два символа из массива stack по индексам top и top-1 и сохранить их в переменных item1 и item2.
        4. Уменьшить указатель top на 2.
        5. Вывести информацию о потоке методе и состоянии стека
        6. Сигнализировать всем потокам, ожидающим на условии stackFullCondition.
        7. Освободить блокировку lock.
        8. Вернуть строку, состоящую из item1 и item2.
    }

    public void printStack() {
        1. Получить блокировку lock.
        2. Если стек пуст, вывести сообщение "Stack is empty".
        3. Иначе, вывести содержимое стека, начиная с индекса 0 до top.
        4. Освободить блокировку lock.
    }

    public boolean isEmpty() {
        1. Вернуть true, если top равен -1, иначе вернуть false.
    }

    public boolean isFull() {
        1. Вернуть true, если top равен CAPACITY - 1, иначе вернуть false.
    }
}
```

Теперь словесные "проекты" включают объявления переменных, доступы и структуру классов. Это дает более полное представление о реализации каждого класса и его методов.