synchronized错误用法

    翻起tomcat5的源码,看到standardServer.java中的addservice方法:

 

    public void addService(Service service) {

 

        service.setServer(this);

 

        synchronized (services) {

            Service results[] = new Service[services.length + 1];

            System.arraycopy(services, 0, results, 0, services.length);

            results[services.length] = service;

            services = results; ---此处会导致同步失效,因为改写了锁的对象,也就是锁指向的区域发生了改变

 

            if (initialized) {

                try {

                    service.initialize();

                } catch (LifecycleException e) {

                    e.printStackTrace(System.err);

                }

            }

 

            if (started && (service instanceof Lifecycle)) {

                try {

                    ((Lifecycle) service).start();

                } catch (LifecycleException e) {

                    ;

                }

            }

 

            // Report this property change to interested listeners

            support.firePropertyChange("service", null, service);

        }

 

    }

    由于Thread.Sleep()不会失去拥有的对象锁,做个例子验证一下

        public class Test {

 

        private static Object lock = new Object();

        public static void main(String[] args) {

 

        new Thread(){

                public void run() {

                       synchronized (lock) {

                             System.out.println("thread1-----enter");

                             lock = new Object() ; //更换锁的对象

                             try {

                                   Thread.sleep(3000); //让线程2可以运行,看是否能进入代码块

                             } catch (InterruptedException e) {

                                    e.printStackTrace();

                             }

                             System.out.println("thread1-----exit");

                      }

               }

        }.start();

        new Thread(){

                public void run() {

                      try {

                            Thread.sleep(1000);//让上面的线程1先进入同步代码块

                      } catch (InterruptedException e) {

                            e.printStackTrace();

                      } 

                      synchronized (lock) {

                              System.out.println("thread2-----enter");

                              System.out.println("thread2-----exit");

                      }

             }

       }.start();

    }

}

输出的结果为

thread1-----enter

thread2-----enter

thread2-----exit

thread1-----exit

可见上面的同步失败,连写tomcat的大牛都出错,synchronized的坑真不小。

<think>嗯,用户问的是Javasynchronized用法和案例。首先,我需要回忆一下synchronized的基本概念。synchronizedJava中是用来控制多线程对共享资源的访问,避免线程冲突和数据不一致的问题。主要的作用是确保同一时间只有一个线程可以执行某个方法或代码块。 接下来,我得考虑synchronized的几种使用方式。常见的应该有三种:实例方法同步、静态方法同步同步代码块。实例方法同步是给当前对象实例加锁,而静态方法同步则是给类的Class对象加锁,因为静态方法属于类级别。同步代码块的话,可以更灵活地指定锁对象,这样可以在不同的代码块使用不同的锁,提高并发效率。 然后,每个使用方式都需要具体的例子来说明。比如实例方法同步,可以举一个计数器类的例子,多个线程调用increment方法,如果不加synchronized的话,可能会出现计数错误。加上synchronized后,就能保证原子性操作。 静态方法同步的例子可能需要一个静态计数器,同样用多个线程来测试。同步代码块的话,可以演示使用不同的锁对象,或者使用this和类对象,这样用户能理解不同锁的作用范围。 另外,需要提到锁的释放机制。synchronized是自动获取和释放锁的,进入同步块或方法时获取,退出时释放,无论是正常退出还是异常退出,这样能避免死锁的情况,不过实际开发中还是要注意锁的嵌套问题。 可能用户还会关心synchronized的底层实现,比如monitor机制,对象头中的monitor指针,以及JVM如何管理锁的获取和释放。不过这部分可能属于进阶内容,用户如果没有问的话,可能不需要深入,但可以稍微提一下,让回答更全面。 案例部分要具体,最好是能运行的代码示例,这样用户能直接看到效果。比如计数器类,创建多个线程,每个线程循环增加计数,最后输出结果,对比加锁和不加锁的情况下的结果差异。这样用户能直观地理解synchronized的作用。 还要注意可能存在的误区,比如锁对象的选择。如果同步代码块使用不同的锁对象,可能无法正确同步,导致线程安全问题。比如如果两个线程分别使用不同的锁对象,那么它们的同步块不会互斥,这时候需要确保所有线程使用的是同一个锁对象。 另外,synchronized的可重入性也是一个点,同一个线程可以多次获取同一个锁,不会自己阻塞自己,这在递归调用或者多个同步方法互相调用时很重要。 最后,总结一下synchronized的优缺点。优点是使用简单,自动管理锁,不容易出错;缺点是性能相比Lock接口可能稍差,尤其是在高竞争环境下,但现代JVM对synchronized做了很多优化,比如偏向锁、轻量级锁、自旋锁等,所以性能差距已经缩小了很多。 在写案例的时候,要确保代码正确,语法无误,特别是同步块的作用范围是否正确,锁对象是否恰当。例如,在同步代码块的例子中,使用this和Counter.class作为锁对象的不同场景。 可能还需要提醒用户,虽然synchronized能解决线程安全问题,但过度使用会导致性能下降,因为同一时间只有一个线程能执行同步代码,所以要根据实际情况合理设计同步范围,尽量减少同步的代码量,提高并发性能。 总之,回答的结构需要先介绍synchronized的作用,然后分点讲解不同的使用方式,每种方式给出示例代码,并解释代码的执行结果和原理,最后总结注意事项和最佳实践。</think>以下为分步讲解`synchronized`的用法和案例: --- ### 一、synchronized 核心作用 保证**多线程环境下**对共享资源的**原子性**和**可见性**,避免数据竞争和状态不一致。 --- ### 二、三种使用方式及案例 #### 1. 同步实例方法 - **锁对象**:当前实例(`this`) - **适用场景**:保护非静态变量的线程安全 ```java class Counter { private int count = 0; // 同步实例方法 public synchronized void increment() { count++; // 原子操作 } public int getCount() { return count; } } // 测试代码 public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(counter.getCount()); // 输出 2000 } ``` --- #### 2. 同步静态方法 - **锁对象**:类的`Class`对象(`Counter.class`) - **适用场景**:保护静态变量的线程安全 ```java class StaticCounter { private static int count = 0; // 同步静态方法 public static synchronized void increment() { count++; } public static int getCount() { return count; } } // 测试代码(类似实例方法测试,所有线程共享静态方法) ``` --- #### 3. 同步代码块 - **锁对象**:可指定任意对象(推荐使用专用锁对象) - **优势**:缩小同步范围,提高性能 ```java class BlockCounter { private int count = 0; private final Object lock = new Object(); // 专用锁对象 public void increment() { synchronized (lock) { // 显式指定锁对象 count++; } } } // 其他用法 public void method() { // 同步当前实例 synchronized (this) { // ... } // 同步类对象 synchronized (BlockCounter.class) { // ... } } ``` --- ### 三、底层原理 通过**对象监视器(Monitor)**实现: 1. 每个Java对象关联一个Monitor 2. 线程执行`synchronized`代码前需获取Monitor锁 3. 获取成功则标记为锁定状态,其他线程进入阻塞队列 --- ### 四、关键注意事项 1. **锁对象一致性**:所有线程必须使用**同一个锁对象**才能生效 2. **避免锁粒度问题**:同步范围过大降低性能,过小导致线程不安全 3. **可重入性**:同一线程可重复获取已持有的锁 4. **非公平锁**:默认抢占顺序不保证公平性 --- ### 五、典型应用场景 1. 单例模式(双重检查锁) ```java public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 2. 线程安全的集合操作 ```java List<String> syncList = Collections.synchronizedList(new ArrayList<>()); ``` --- ### 六、与Lock的区别 | 特性 | synchronized | Lock接口 | |--------------------|--------------------|--------------------| | 获取方式 | 自动获取/释放 | 需手动lock/unlock | | 可中断 | 否 | 是 | | 公平性 | 非公平 | 可配置 | | 条件变量 | 单一等待队列 | 支持多个Condition | --- 通过合理使用`synchronized`,可以有效解决多线程环境下的线程安全问题。实际开发中应根据具体场景选择同步策略,并注意控制锁粒度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值