synchronized

了解一下,一个线程中是否可以调用多个synchronized方法(包含方法,静态方法,代码块)


```java
public class SyncTest {
    //获取CPU个数
    private static int cpuCount = Runtime.getRuntime().availableProcessors();
    private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(cpuCount, cpuCount * 2, 20,
            TimeUnit.SECONDS, new LinkedBlockingQueue<>(20000));

    static {
        System.out.println("我的cpu颗数: " + cpuCount);
    }

    //成员变量,可被多个线程 共享
    private static long a = 0L;
    private static long b = 0L;
    private static long c = 0L;

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(10000);
        SyncTest lockobj = new SyncTest();
        for (int i = 0; i < 10000; i++) {
            threadPool.execute(() -> {
                lockobj.sync(countDownLatch);
                sync2(countDownLatch);
                lockobj.sync3(countDownLatch);
            });
        }
        // 等待所有的线程执行完再打印
        countDownLatch.await();
        System.out.println("a=" + a);
        System.out.println("b=" + b);
        System.out.println("c=" + c);
    }

    /**
     * 修饰生源方法,其使用的锁对应时当前类所在的实例对象(或者说当前方法的调用对象),也就是this
     *
     * @param countDownLatch
     */
    private synchronized void sync(CountDownLatch countDownLatch) {
        try {
            a++;
        } finally {
            countDownLatch.countDown();
        }
    }

    /**
     * 修饰静态方法,使用的锁对象是当前类
     *
     * @param countDownLatch
     */
    private synchronized static void sync2(CountDownLatch countDownLatch) {
        try {
            b++;
        }  finally {
            countDownLatch.countDown();
        }
    }

    private void sync3(CountDownLatch countDownLatch) {
        try {
            synchronized (countDownLatch) {
                c++;
            }
        }  finally {
            countDownLatch.countDown();
        }
    }

}

结果:
a=3339
b=3334
c=3332

比如上面这段代码,如果三个代码在同一个线程,甚至两个代码在同一个线程,得出的结果集都不正确。

你的结果不对,是因为你的线程还没结束,你就输出结果了,不要用countDownLatch.await();
用threadPool.getActiveCount()判断它是不是执行完了,只要不等于0,就是还没结束
这一段改一下

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(10000);
        SyncTest lockobj = new SyncTest();
        for (int i = 0; i < 10000; i++) {
            threadPool.execute(() -> {
                lockobj.sync(countDownLatch);
                sync2(countDownLatch);
                lockobj.sync3(countDownLatch);
            });
        }

        while (threadPool.getActiveCount()!=0){
            Thread.sleep(100);
        }

        threadPool.shutdown();

        System.out.println("a=" + a);
        System.out.println("b=" + b);
        System.out.println("c=" + c);
    }

img

在Java中,一个线程可以在同一时间调用多个synchronized方法(包括实例方法、静态方法和代码块)。每个synchronized方法都会获取相应的锁,以确保同一时间只有一个线程可以执行该方法。不同的synchronized方法可能使用不同的锁对象,但它们之间的互斥性是保证的。

在你提供的示例代码中,三个方法都使用了synchronized关键字修饰,分别对应不同的锁对象。这意味着在同一时间内,只能有一个线程执行其中一个synchronized方法。如果多个线程同时调用这三个方法,它们之间的执行顺序是不确定的,但每个方法内部的操作是原子性的。

关于你提到的结果不正确的问题,可能是因为线程之间的并发执行导致的。由于线程调度的不确定性,每个线程在获取到锁之前都可能被其他线程抢占执行。这可能导致某些线程在获取锁之前已经执行完毕,从而导致计数不准确。

为了解决这个问题,你可以使用同步工具类如CountDownLatch来确保所有线程执行完毕后再打印结果。在你的代码中,你已经使用了CountDownLatch来等待所有线程执行完毕,但可能存在其他并发问题导致结果不准确。你可以尝试在sync、sync2和sync3方法内部加上一些打印语句来观察每个线程的执行情况,以便更好地排查问题所在。

另外,你在代码中使用了线程池来执行任务,这会进一步增加并发执行的可能性。确保线程池的大小适当,以免造成过多的线程竞争和调度开销。