同步块上的Java线程锁

同步块上的Java线程锁,java,multithreading,Java,Multithreading,我正在学习带锁的同步块。我想知道这个锁和程序中提供的某些第三方锁之间的区别 public class NewThread extends Thread { StringBuffer sb; NewThread(StringBuffer sb){ this.sb=sb; } public void run(){ synchronized(this.sb){ for(int i=0;i<1000;i++){ System.out.prin

我正在学习带锁的同步块。我想知道这个锁和程序中提供的某些第三方锁之间的区别

public class NewThread extends Thread {
StringBuffer sb;
NewThread(StringBuffer sb){
    this.sb=sb;
}
public void run(){
    synchronized(this.sb){
        for(int i=0;i<1000;i++){
            System.out.print(sb);
               try{
             Thread.sleep(5*60);
        }
        catch(Exception e){}
        }
       char c = this.sb.charAt(0);
       this.sb.setCharAt(0, ++c);
    }
}
public static void main(String[] args){
    StringBuffer sb=new StringBuffer("A");
    NewThread nt=new NewThread(sb);
    NewThread nt1=new NewThread(sb);
    NewThread nt2=new NewThread(sb);
    nt.start();
    nt1.start();
    nt2.start();
}
public类NewThread扩展线程{
对某人施加压力;
新线程(StringBuffer sb){
这个;
}
公开募捐{
(这是某人){

对于(inti=0;i,在Java中,每个对象都可以用作互斥对象(请参阅)。这意味着在任何时候只有一件事情可以在对象上同步,您使用的对象通常是不相关的,尽管它应该尽可能具体。例如,如果多个线程正在访问一个列表,您应该在该列表上同步,而不是在整个对象上同步(此)以便其他需要对象中其他内容的对象可以访问它。


我认为关于互斥的文章可能有助于澄清这一问题。本质上,只有一个线程可以获得“锁”的钥匙--该锁是内部同步的。只要访问您的资源的所有东西都请求对同一对象的锁,您就受到保护。

如果您有通用操作系统API(例如Linux中的pthread库)的并发开发经验,您可能知道我们应该使用锁或其他数据结构来同步进程es/线程访问关键部分(可修改共享对象)

Java使用锁来实现同步块。同步块是一种封装与锁相关的繁琐操作的机制(在操作系统中称为监视器)。每个对象在Java中都有一个锁。同步时,共享对象中的锁首先被锁定(也可以说其他进程需要共享对象的锁)。如果某个线程无法获取锁,这意味着某个其他线程正在持有锁,它必须等待其他线程释放锁,然后重新获取,直到它持有锁,然后进入临界区

第一个代码段在StringBuffer实例中使用lock,即sb,每个线程将尝试获取sb的锁(在运行代码之前调用lock_of_sb.lock()。只有成功获取了sb的锁的线程才能最终执行代码

至于第二个代码,相当于

public synchronized void run(){
  for(int i=0;i<1000;i++){
      System.out.print(sb);
         try{
       Thread.sleep(5*60);
  }
  catch(Exception e){}
  }
  char c = this.sb.charAt(0);
  this.sb.setCharAt(0, ++c);
}
public synchronized void run(){

对于(int i=0;i其他人已经回答了,但要加上我的2美分

a) 第一个示例是ok,因为
synchronized
关键字保护
StringBuffer
线程共享一个锁

b) 第二个例子是不正确的。你给每个线程一个不同的锁。实际上,它没有任何效果(事实上,现代Java编译器完全删除了这样的锁)。如果有多个线程使用它,锁是有意义的

你可以这样想:
如果你共用一个浴室,你最好为浴室配备一把锁(比如它的门钥匙)。如果你让每个人在使用浴室之前都锁上自己的iPhone,那肯定是没有用的。请注意,共享外观不需要是门钥匙。你不妨选一个iPhone作为浴室的“钥匙”(每个人在使用浴室前都必须锁上iPhone,只有锁上的人才能解锁)。在现实生活中,这听起来很荒谬,但这就是我们使用互斥锁所做的


c) 第二个示例可能被认为是错误的,但在实践中,您看不到竞争条件的影响。这是因为
StringBuffer
在内部进行同步。如果改用
StringBuilder
,您可能会看到竞争条件(取决于运行时条件).

Satheesh,您的示例仅在它们锁定的对象上有所不同。在第一个示例(this.sb)中,这意味着一次只能有一个线程位于同步(this.sb){}块内。第二个示例意味着只有一个线程位于同步(this){}块内块。使用哪一个取决于-您想阻止线程同时访问整个对象,还是只访问字符串缓冲区?先生..我了解到当同步块启动时,调用的对象上会有锁。但是这里如果我们给这个。sb,u是否意味着多个线程进入同步块,并且只有它无法访问sb对象…?两者都可以正常工作。区别仅在于您要求他们拥有的密钥——对象的密钥或StringBuffer的密钥。这就是同步(var)所做的,要求人们拥有“var”锁的密钥(只有一个)为了在里面输入代码。一旦在里面完成了,密钥就会给第一个得到它的线程。谢谢,我理解了..但是我没有得到共享锁或共享锁..你能解释一下吗that@satheesh我不知道这是否是您想要的:在同步的多线程/进程系统中,通常一种资源只能存在一个锁.用于控制共享对象。在linux中,锁和共享对象是分开的。而在Java中,每个对象都有自己的锁(可以在class object的源代码中找到).也许在linux中,我们可以说某个进程共享一个锁,因为锁和进程/线程之间没有关系。但是在Java中,由于每个对象都有自己的锁,所以不需要显式共享锁。锁是由对象隐式维护的。尽管问吧。好的,我明白了..但是与linux相关的每件事我都有点困惑@satheesh如果我的回答让你感到困惑,我很抱歉。我在Linux中编写的C代码比Java:-)多,而且同步问题实际上在操作系统的范围内。太好了。我还在Linux中做一个关于探测器优化的项目
public synchronized void run(){
  for(int i=0;i<1000;i++){
      System.out.print(sb);
         try{
       Thread.sleep(5*60);
  }
  catch(Exception e){}
  }
  char c = this.sb.charAt(0);
  this.sb.setCharAt(0, ++c);
}