Для предыдущего примера будем определять приоритет ресурса по его имени: у кого имя "больше", тот и будет захватываться первым. Для этого класс ITishnik будет имплементировать интерфейс Comparable<T>
abstract class ITishnik implements Comparable<ITishnik> {
String name;
ITishnik(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public int compareTo(ITishnik o) {
String nameIt1 = getName();
String nameIt2 = o.getName();
int comparing = nameIt1.compareTo(nameIt2);
return comparing;
}
}
В класс Application добавим метод, который будет определять приоритет ресурса. Для удобства он будет возвращать очередь ресурсов.
abstract class Application extends Thread {
Developer developer;
Tester tester;
public Application(Developer developer, Tester tester) {
this.developer = developer;
this.tester = tester;
}
protected ArrayDeque<ITishnik> sortResources(ITishnik it1, ITishnik it2) {
// сортируем ресурсы
Set<ITishnik> set = new TreeSet<>();
set.add(it1);
set.add(it2);
return new ArrayDeque<>(set);
}
protected void sleepThread(String lockname) {
try {
System.out.println(this.getName() + " acqured " + lockname);
Thread.sleep((long) Math.random() * 1000L);
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
Изменим метод run() для приложений, добавив захват ресурсов в соответствии с приоритетом.
class AndroidApp extends Application {
public AndroidApp(Developer developer, Tester tester) {
super(developer, tester);
this.setName("AndroidApp");
}
@Override
public void run() {
ArrayDeque<ITishnik> queue = sortResources(developer, tester);
ITishnik firstLockObject = queue.getFirst();
ITishnik seckondLockObject = queue.getFirst();
synchronized (firstLockObject) {
sleepThread(firstLockObject.getName());
synchronized (seckondLockObject) {
tester.testApp();
developer.fixBugs();
}
}
}
}
class iPhoneApp extends Application {
public iPhoneApp(Developer developer, Tester tester) {
super(developer, tester);
this.setName("iPhoneApp");
}
@Override
public void run() {
ArrayDeque<ITishnik> queue = sortResources(developer, tester);
ITishnik firstLockObject = queue.getFirst();
ITishnik seckondLockObject = queue.getFirst();
synchronized (firstLockObject) {
sleepThread(firstLockObject.getName());
synchronized (seckondLockObject) {
developer.code();
tester.testApp();
}
}
}
}
Программист и тестировщик останутся без изменений
class Developer extends ITishnik {
Developer(String name) {
super(name);
}
void code() {
System.out.println("Developer is coding...");
}
void fixBugs() {
System.out.println("Developer is fixing bugs...");
}
}
class Tester extends ITishnik {
Tester(String name) {
super(name);
}
void testApp() {
System.out.println("Tester is testing...");
}
}
public static void main(String[] args) {
Developer developer = new Developer("Developer");
Tester tester = new Tester("Tester");
AndroidApp android = new AndroidApp(developer, tester);
iPhoneApp iPhone = new iPhoneApp(developer, tester);
android.start();
iPhone.start();
}
Вывод будет такой:
/*
iPhoneApp acqured Developer
Developer is coding...
Tester is testing...
AndroidApp acqured Developer
Tester is testing...
Developer is fixing bugs...
*/
Или такой:
/*
AndroidApp acqured Developer
Tester is testing...
Developer is fixing bugs...
iPhoneApp acqured Developer
Developer is coding...
Tester is testing...
*/