A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张金铎 中级黑马   /  2013-5-6 23:20  /  2406 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

关于synchronized用法的用法,一直不是很清楚,线程锁到底是怎么一回事?是锁类?还是锁方法?什么区别

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

8 个回复

正序浏览
synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
  1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
  public synchronized void accessVal(int newVal);
  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
  synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
  2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
  synchronized(syncObject) {
  //允许访问控制的代码
  }
   synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
  对synchronized(this)的一些理解
  一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
  二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
  三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
  四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
  五、以上规则对其它对象锁同样适用
回复 使用道具 举报

如果问题未解决,请继续追问,如果问题解决了,请将分类改为“已解决”,谢谢
回复 使用道具 举报
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A,没有的话,直接运行 它包括两种用法:synchronized 方法和 synchronized 块。
1. synchronized 方法:
  通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
  public synchronized void accessVal(int newVal);
  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
  synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:
  通过 synchronized关键字来声明synchronized 块。语法如下:
  synchronized(syncObject) {
  //允许访问控制的代码
  }
  synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
对synchronized(this)的一些理解
  一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
  三、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的除synchronized(this)同步代码块以外的部分。
  四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
  五、以上规则对其它对象锁同样适用

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
首先,楼主要明白使用并发(线程)会出现的问题。
第一:合作同步
合作同步可以用简单的生产者和消费者的问题来说明,一个程序单元生成某个数据值或者某项资源另一个程序要使用,
生成的数据通常由生产单元放在存储缓冲区中,由消费单元从缓冲区中移除。向缓冲区中移除的顺序必须同步。如果缓冲区是空的,消费单元就不允许
从缓冲区中取数据。同样的当缓冲区满时,生产单元不允许往缓冲区存放新的数据,这就是合作同步的问题。
解决办法:可以使用wait(),notify()和notifyAll()方法实现,所有这些方法都在都在根类Object中定义,出了Object以外的所有类都继承了这些方法。
               用notify()方法可以告诉某个等待中的线程,它所等待的事件已经发生,无法确定是哪一个线程被notify()唤醒,因为虚拟机随机从线程对象的等待列表
                中选择一个线程。所以通常使用notifyAll()方法唤醒对象等待列表中的所有线程,在他们调用wait()后立即开始执行。
                wait(),notify(),notifyAll()方法可以只在同步方法中调用,因为他们使用了由同步方法放置在对象上的锁。而对wait()的调一般是放在while()中,由方法
                 等待的条件来控制。
第二:竞争同步
这里假设现在有一个为num的int的共享数据,它的初始值是3,现在有两个线程要对其进行运算,A线程要对其进行+1,而B线程要对其*2,
假如他们没有竞争同步,根据他们的顺序,这些操作就可能导致4种不同的结果。
①如果A在B获取num之前完成num运算,那么最后的值是8
②如果A在运算之前获取num时,B也获取了num值,那么就可能导致另外2种的值
         1,假如A比B先完成运算,那么值是6。(A把值+1,num=4,而B进行*3运算完后,把A运算出来的值覆盖了,num=6)
         2,假如A比B后完成运算,那么值是4。(B把值*3,num=6,而A把值进行+1,完后把B算出来的值覆盖了,num=4)
③如果B在A获取num值之前完成运算,num的值将是7。
因为两个或者更多的任务竞争使用共享支援,程序的表现取决于哪一个任务先到达,竞争同步的重要性现在就应该很清楚了
解决办法:我们可以用一个锁来解决此类的问题,两个或更多的方法被同一个锁锁住并且持共同的钥匙,他们谁持有钥匙那么其它在持有钥匙
                的线程执行完之前不能进入被锁住的内容,synchronized的作用就体现出来了。
格式:
synchronized(表达式){
语句
}
其中,表达式必须对一个对象求值,语句可以是单条语句或者是复合语句。对象在语句或或复合语句执行时被枷锁。
定义有同步方法的对象必须有一个相关联的队列,当同步方法操作时,将其他试图执行它的同步方法储存起来,这队列是隐式提供的。
当同步方法完成了在对象上的执行,那么在对象等待队列中等待的方法(如果有的话)就被放入任务的就绪队列

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
synchronized是线程锁,是为了解决多线程的安全问题而产生的。
多线程是不安全的,这是一个主要的原因,所以必须有一个机制能够保证多线程的情况下的程序运行的安全,所以synchronized出现了,就是为了锁住需要同步的代码,不让多线程同时的运行这个同步的代码。
使用:1.可以说这个sychronized是一个方法的修饰符,因为synchronized可以用来修饰方法,这时候,这个被修饰的方法中的代码就全部成为了需要同步的代码。
         2.可以是仅仅锁住需要同步的代码,使用方法synchronized(对象){ 代码块}
需要使用哪种方法,根据程序的具体情况而定,如果整个方法中的代码都是需要同步的,那就是用第一种方法,如果仅仅只是一两句语句需要同步,就使用第二种方法。
  我说的有什么错误的地方,请大家指正,谢谢了。
回复 使用道具 举报
学习学习{:soso_e113:}
回复 使用道具 举报
1、synchronized关键字的作用域有二种:
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。

2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个代码块中,即表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){需要同步的代码},它的作用域是当前对象;

3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
可以锁方法,也可以锁代码块,对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了专业的解决方式,就是同步代码块。
哪些代码需要同步就看哪些代码操作共享数据
Synchronized(对象){
需要同步的代码
}

对象如同锁,持有锁的线程可以再同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。同步可以解决线程的安全问题,同步的前提:
1、 必须要有两个或者两个以上的线程才需要同步。
2、 必须是多个线程使用同一个锁。
3、 必须保证同步中只能有一个线程在运行。
同步的好处和弊端:
好处:解决了多线程的安全问题
弊端:多个线程都需要判断锁,较为消耗资源。

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马