sychronized对象锁和类锁的区别

对象锁

public class MultiThred  {

      int tag =0;
       synchronized void print_num(String num) {
          try {
                if("a".equals(num)){
                    tag = 100;
                    System.out.println(" num is "+tag );
                    Thread.sleep(2000);

                }else{
                    tag =200;
                    System.out.println(" num is "+tag );

                }
                System.out.println("thread "+num+" is over");
        } catch (InterruptedException e) {
            // TODO: handle exception
        }


    }
    public static void main(String[] args) {
        final MultiThred t1 = new MultiThred();

        final MultiThred t2 = new MultiThred();

        Thread mt1 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    t1.print_num("a");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        Thread mt2 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    t2.print_num("b");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        mt1.start();
        mt2.start();
    }
}

运行程序输出结果为

 num is 200
 num is 100
thread b is over
thread a is over

结果表明thread a 和thread b 是独立运行的,并没有产生a线程阻塞b线程的效果,原因是t1和t2是连两个对象,而sychronized是对象锁,只能对对象内的值进行加锁,所以此时锁对两个对象的操作无效

类锁

代码

public class MultiThred  {

     static int tag =0;
       static synchronized void print_num(String num) {
          try {
                if("a".equals(num)){
                    tag = 100;
                    System.out.println(" num is "+tag );
                    Thread.sleep(2000);

                }else{
                    tag =200;
                    System.out.println(" num is "+tag );

                }
                System.out.println("thread "+num+" is over");
        } catch (InterruptedException e) {
            // TODO: handle exception
        }


    }
    public static void main(String[] args) {
        final MultiThred t1 = new MultiThred();

        final MultiThred t2 = new MultiThred();

        Thread mt1 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    t1.print_num("a");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        Thread mt2 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    t2.print_num("b");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        mt1.start();
        mt2.start();
    }
}

此时结果为

 num is 100
thread a is over
 num is 200
thread b is over

Thread b直到Thread a 执行完才会执行,

为什么static修饰的sychronized方法是类锁

某博客是这样写的

一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。

取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。
对于对象来说,相关联的监视器保护对象的实例变量。
对于类来说,监视器保护类的类变量。
(如果一个对象没有实例变量,或者一个类没有变量,相关联的监视器就什么也不监视。)
为了实现监视器的排他性监视能力,java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。
但是如果线程获取了锁,那么在它释放这个锁之前,就没有其他线程可以获取同样数据的锁了。(锁住一个对象就是获取对象相关联的监视器)
类锁实际上用对象锁来实现。当虚拟机装载一个class文件的时候,它就会创建一个java.lang.Class类的实例。当锁住一个对象的时候,实际上锁住的是那个类的Class对象。
一个线程可以多次对同一个对象上锁。对于每一个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减 1,当计数器值为0时,锁就被完全释放了。
java编程人员不需要自己动手加锁,对象锁是java虚拟机内部使用的。
在java程序中,只需要使用synchronized块或者synchronized方法就可以标志一个监视区域。当每次进入一个监视区域时,java 虚拟机都会自动锁上对象或者类。

synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问该实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于 this.synchronized

参考自
Java对象锁和类锁全面解析(多线程synchronized关键字)
博客园首页新随笔联系管理订阅
synchronized与static synchronized 的区别

### 回答1: 在Java编程语言中,synchronized和lock都是用于实现线程同步的机制,但它们有一些区别。 synchronized是Java语言内置的关键字,用于在方法或代码块级别上实现线程同步。当一个线程进入一个synchronized方法或代码块时,它将获得该方法或代码块的,其他线程将被阻塞,直到该线程释放。synchronized是隐式的,即由Java虚拟机自动管理,因此使用synchronized的代码通常更简单。 相比之下,Lock是Java编程语言中的一个接口,它提供了一组方法来实现线程同步。与synchronized不同,Lock是显式的,需要程序员手动获取和释放。这使得Lock比synchronized更灵活,因为它允许程序员更好地控制线程的行为,如尝试获取的超时时间,可以在多个条件上等待等等。 总的来说,synchronized适用于简单的线程同步问题,而Lock适用于更复杂的线程同步场景。同时,由于Lock提供了更多的控制和灵活性,因此在某些情况下它可能比synchronized更高效。 ### 回答2: synchronized和lock都可以用于多线程编程中的同步机制,但是它们有一些区别。 首先,synchronized是Java语言提供的关键字,而lock是一个接口,属于Java的Lock接口族的一员。这意味着synchronized是Java语言的一部分,而lock是Java提供的一个类库。 其次,synchronized是隐式的,通过使用synchronized关键字来表示代码块的同步,而lock是显式的,通过Lock接口的实现类来实现代码块的同步。 第三,synchronized只有一种使用方式,即使用synchronized关键字对整个代码块进行同步,而lock提供了更多的灵活性和功能,例如可以实现读写分离、公平等。此外,lock还提供了tryLock()方法,可以非阻塞地尝试获取,而synchronized则是阻塞的。 第四,synchronized在发生异常时会自动释放,而lock需要手动释放,如果没有正确释放,可能导致死或资源泄露等问题。 第五,synchronized可以作用于代码块、方法,或者作为类锁;而lock只能作用于代码块。 总结来说,synchronized是Java语言提供的关键字,适用于普通的同步需求,而lock是一个类库接口,提供了更灵活、功能更强大的同步机制。在开发中,可以根据具体情况选择使用synchronized或lock来实现多线程的同步。 ### 回答3: synchronized和lock都是用来控制多线程访问共享资源的机制,但它们在实现上有一些区别。 首先,synchronized是Java语言提供的原生关键字,而lock是通过Lock接口及其实现类ReentrantLock来实现的。synchronized是隐式,它的获取和释放是由JVM自动完成的,而lock是显式,需要手动获取和释放。 其次,在使用上,synchronized是非公平,它允许不按顺序地获取,而lock可以选择性地使用公平或非公平。公平是指多个线程按照申请的顺序获取,而非公平是允许线程跳过等待队列直接获取。 另外,lock比synchronized更加灵活。它提供了一些功能,例如可中断、可轮询以及超时等待等。使用lock可以更好地控制线程的等待时间,避免线程长时间阻塞。 此外,synchronized是基于对象,每个对象都有一个与之关联的监视器。而lock可以同时对多个对象进行加操作,提供了更细粒度的控制。 然而,由于synchronized是Java语言提供的原生支持,使用起来更加简单,不需要显示地获取和释放,而lock需要手动控制。因此,当不需要使用lock提供的额外功能时,推荐使用synchronized来简化代码的复杂度。 总之,synchronized和lock都可以实现多线程间的同步,但在使用方式、灵活性和粒度控制上有一些区别,开发者可以根据实际需求选择适合的机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值