Pits for synchronized lock objects

Keywords: Java Lombok

Today, I wrote something else. I happened to write synchronized. I didn't expect it to fall into the pit. Don't laugh.

At first, the code was like this:

package com.ripplechan.part_1_2_3;

import java.util.concurrent.CountDownLatch;

/**
 * @author RippleChan
 * @date 2018-09-20
 * @time 18:05
 */
public class DataTest {

    public static void main(String[] args) throws InterruptedException {
        int count = 10000;
        CountDownLatch countDownLatch = new CountDownLatch(count * 1);
        Cal cal = new Cal(countDownLatch);
        for (int i = 0; i < count; i++) {
            new Thread(cal).start();
        }
        countDownLatch.await();
        System.out.println(cal.getSum());
    }

}

class Cal extends Thread {

    private Long sum = 0L;
    CountDownLatch countDownLatch;

    public Cal(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        synchronized (sum) {
            try {
                this.sum = sum + 1;
            }  finally {
                countDownLatch.countDown();
            }
        }
    }

    public Long getSum() {
        synchronized (sum) {
            return sum;
        }
    }

}

What do you think is the answer? Why is that? How to avoid this situation?

Look at the following code, I believe you will understand why.

public class DatSalfByObject {

    public static void main(String[] args) throws InterruptedException {
        Long a = 1L;
        int i = System.identityHashCode(a);
        System.out.println(i);
        a = a + 1L;
        int i1 = System.identityHashCode(a);
        System.out.println(i1);
    }

}

Through the guidance of some big guy, I got the following concentration plan:

1. Create a useless object as a public lock;
2. Lock this directly (the lock method is essentially the same as lock this);
3. Encapsulate the object to be modified again;

Option 1:

class MyCal4 extends Thread {

    private Long sum = 0L;
    Object object = new Object();
    CountDownLatch countDownLatch;

    public MyCal4(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            synchronized (object) {
                this.sum = sum + 1;
            }
        }finally {
            countDownLatch.countDown();
        }
    }

    public Long getSum() {
        try {
            synchronized (object) {
                return sum;
            }
        }finally {
        }
    }
}

Option 2:

class MyCal5 extends Thread {

    private Long sum = 0L;
    CountDownLatch countDownLatch;

    public MyCal5(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            synchronized (this) {
                this.sum = sum + 1;
            }
        }finally {
            countDownLatch.countDown();
        }
    }

    public Long getSum() {
        try {
            synchronized (this) {
                return sum;
            }
        }finally {
        }
    }

}

Option 3:

@Data
class User {

    private Long id = 0L;

}

class UserThread extends Thread {

    private User user;
    private CountDownLatch countDownLatch;

    public UserThread(User user,CountDownLatch countDownLatch) {
        this.user = user;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            synchronized (user) {
                Long id = user.getId();
                user.setId(id + 1);
            }
        }finally {
            countDownLatch.countDown();
        }
    }

}

In the end, because locking this consumes too much, it is recommended to lock objects, but how to avoid objects being modified? It's time to test the Java se foundation. The code is as follows:

package com.ripplechan.part_1_2_3;

import lombok.Data;

import java.util.concurrent.CountDownLatch;

/**
 * @author RippleChan
 * @date 2018-09-20
 * @time 17:38
 */
public class DatSalfByObject {

    public static void main(String[] args) throws InterruptedException {
        int count = 10000;
        User user = new User();
        CountDownLatch countDownLatch = new CountDownLatch(count);
        UserThread userThread = new UserThread(user, countDownLatch);
        for (int c = 0; c < 10000; c++) {
            new Thread(userThread).start();
        }
        countDownLatch.await();
        System.out.println(user.getId());
    }

}


@Data
class User {

    private Long id = 0L;

}

class UserThread extends Thread {

    private final User user;
    private final CountDownLatch countDownLatch;

    public UserThread(User user,CountDownLatch countDownLatch) {
        this.user = user;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            synchronized (user) {
                Long id = user.getId();
                user.setId(id + 1);
            }
        }finally {
            countDownLatch.countDown();
        }
    }

}

Yes, final decoration, ha ha, this is a lock to prevent mistakes.

Posted by Neoraven456 on Sat, 28 Dec 2019 11:30:12 -0800