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.
}
}
```
Теперь словесные "проекты" включают объявления переменных, доступы и структуру классов. Это дает более полное представление о реализации каждого класса и его методов.