Если в объекте определены методы, выполняющие несвязанные друг с другом задачи, то в случае захвата монитора одним потоком, второй поток всё равно будет вынужден ждать его высвобождения.
class Post {
private int countComments;
private int countLikes;
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern(" mm:ss:n");
public synchronized void countCommentsIncrease() {
printWhoBlockedMonitor();
sleep(1000L);
countComments++;
System.out.println("countComments: " + countComments);
}
public synchronized void plusOneLike() {
printWhoBlockedMonitor();
sleep(20L);
countLikes++;
System.out.println("countLikes: " + countLikes);
}
private void printWhoBlockedMonitor() {
String threadName = Thread.currentThread().getName();
System.out.println("Monitor is blocked by " + threadName
+ LocalDateTime.now().format(formatter));
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
ex.printStackTrace(System.out);
}
}
}
abstract class Manager extends Thread {
Post post;
String name;
long startTime;
long endTime;
Manager(Post post) {
this.post = post;
}
@Override
public void run() {
name = Thread.currentThread().getName();
startTime = System.currentTimeMillis();
action();
endTime = System.currentTimeMillis();
System.out.println(name + ": Spent " + (endTime - startTime) + " ms");
}
abstract void action();
}
class CommentsManager extends Manager {
CommentsManager(Post post) {
super(post);
}
@Override
void action() {
post.countCommentsIncrease();
}
}
class LikesManager extends Manager {
LikesManager(Post post) {
super(post);
}
@Override
void action() {
post.plusOneLike();
}
}
Post post = new Post();
Thread mComments = new CommentsManager(post);
Thread mLikes = new LikesManager(post);
mComments.start();
mLikes.start();
/*
Monitor is blocked by Thread-0 52:04:225000000
countComments: 1
Monitor is blocked by Thread-1 52:05:239000000
Thread-0: Spent 1045 ms
countLikes: 1
Thread-1: Spent 1076 ms
*/
Чтобы избежать такого бесполезного простоя, синхронизацию методов можно выполнять на разных объектах. Перепишем класс Post так:
class Post {
private int countComments;
private int countLikes;
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern(" mm:ss:n");
private Object ObjComments = new Object();
private Object ObjLikes = new Object();
public void countCommentsIncrease() {
synchronized (ObjComments) {
printWhoBlockedMonitor();
sleep(1000L);
countComments++;
System.out.println("countComments: " + countComments);
}
}
public synchronized void plusOneLike() {
synchronized (ObjLikes) {
printWhoBlockedMonitor();
sleep(20L);
countLikes++;
System.out.println("countLikes: " + countLikes);
}
}
private void printWhoBlockedMonitor() {
/* ... */
}
private void sleep(long delay) {
/* ... */
}
}
/*
Monitor is blocked by Thread-1 54:24:954000000
Monitor is blocked by Thread-0 54:24:954000000
countLikes: 1
Thread-1: Spent 62 ms
countComments: 1
Thread-0: Spent 1045 ms
*/