Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
双线程Java多线程同步方法_Java_Multithreading_Synchronized - Fatal编程技术网

双线程Java多线程同步方法

双线程Java多线程同步方法,java,multithreading,synchronized,Java,Multithreading,Synchronized,我有一个非常简单的代码,但无法理解 public class Test extends Thread { public synchronized void testPrint() { System.out.println("I am sleeping..." + Thread.currentThread().getName()); try {

我有一个非常简单的代码,但无法理解

    public class Test extends Thread {
    
        public synchronized void testPrint() {
            System.out.println("I am sleeping..."
                    + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
                System.out.println("I am done sleeping..."
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void run() {
            Test t = new Test();
            t.testPrint();
    
            System.out.println("I am out..." + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Test t1 = new Test();
            Test t2 = new Test();
    
            t1.start();
            t2.start();
    
        }
    }
这是我的问题

当两个线程执行
Test t=new Test()
时,是否会创建两个同名的不同对象?多线程的这一行发生了什么? 我的成绩不理想

我正在睡觉…线程0

我在睡觉……一号线

我睡不着了…线程0

我出局了……0号线

我已经睡不着了…一号线

我出局了…一号线


从输出来看,这肯定意味着创建了两个对象,这就是为什么两个线程都可以进入sync方法。希望我的理解是正确的?
系统如何维护这两个对象?

您正在创建两个不同的对象,这两个对象将有两个不同的监视器,在这两个监视器上将获取锁。由于两个线程都在不同的对象上工作,所以无法实现同步

你可以试试

public class Test extends Thread {

Object obj;

public Test(Object obj){
    this.obj = obj;
}

public synchronized void testPrint() {
    System.out.println("I am sleeping..."
            + Thread.currentThread().getName());
    try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..."
                + Thread.currentThread().getName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public void run() {
    ((Test)obj).testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
}

public static void main(String[] args) {

    Object obj = new Test(null);

    Test t1 = new Test(obj);
    Test t2 = new Test(obj);

    t1.start();
    t2.start();

}
}
输出是

I am sleeping...Thread-1
I am done sleeping...Thread-1
I am out...Thread-1
I am sleeping...Thread-2
I am done sleeping...Thread-2
I am out...Thread-2

正如预期的那样。

您正在创建两个不同的对象,这两个对象将有两个不同的监视器,将在其上获取锁。由于两个线程都在不同的对象上工作,所以无法实现同步

你可以试试

public class Test extends Thread {

Object obj;

public Test(Object obj){
    this.obj = obj;
}

public synchronized void testPrint() {
    System.out.println("I am sleeping..."
            + Thread.currentThread().getName());
    try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..."
                + Thread.currentThread().getName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public void run() {
    ((Test)obj).testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
}

public static void main(String[] args) {

    Object obj = new Test(null);

    Test t1 = new Test(obj);
    Test t2 = new Test(obj);

    t1.start();
    t2.start();

}
}
输出是

I am sleeping...Thread-1
I am done sleeping...Thread-1
I am out...Thread-1
I am sleeping...Thread-2
I am done sleeping...Thread-2
I am out...Thread-2

正如预期的那样。

当您运行
Test t=new Test()
jvm在堆上创建新对象,并将带有指向该对象链接的变量t放在当前线程的堆栈上。

当您在两个或多个不同的线程中运行该代码时,每个线程都有自己的堆栈,因此当您运行
Test t=new Test()
jvm在堆上创建新对象并将带有指向该对象链接的变量t放在当前线程的堆栈上时,每个线程都会创建自己的变量t和对象Test。
Test t = new Test()
当您在两个或多个不同线程中运行该代码时,每个线程都有自己的堆栈,因此每个线程都创建自己的变量t和对象Test

Test t = new Test()
这将在堆中创建一个对象,引用将放置在堆栈中

在您的示例中,您根本不需要
synchronized
方法,因为您没有在不同的线程之间共享实例

这将在堆中创建一个对象,引用将放置在堆栈中


在您的示例中,您根本不需要
synchronized
方法,因为您没有在不同的线程之间共享实例。

使用当前方法,您可以确保对于
Test
的每个实例,方法
testPrint()
不能同时运行。这完全取决于你想做什么。我假设您希望保护
testPrint()
方法,使其不在多个线程中同时运行,同时使用
Test
的多个实例

目前,您直接在方法上使用
synchronized
关键字。这将导致使用对象本身(测试的一个实例)进行同步

您应该在
Test
实例之间共享的另一个对象上进行同步(例如,您可以使锁对象成为静态的)

另外请注意,通常最好只实现
Runnable
接口,然后将实现传递给线程。 另外,您不必每次运行时都创建一个新的
Test
实例(我看不出这样做的目的),我对此进行了注释

public class Test extends Thread {
  // could also use a static monitor instead.
  // private static final Object monitor = new Object();
  private final Object monitor;

  public Test(final Object monitor) {
    this.monitor = monitor;
  }

  public void testPrint() {
    synchronized (monitor) {
      System.out.println("I am sleeping..." + Thread.currentThread().getName());
      try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..." + Thread.currentThread().getName());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void run() {
    //Test t = new Test(monitor);
    //t.testPrint();
    testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
  }

  public static void main(String[] args) {
    // synchronization will happen on this object.
    final Object monitor = new Object();

    Test t1 = new Test(monitor);
    Test t2 = new Test(monitor);

    t1.start();
    t2.start();

  }
}

使用当前方法,可以确保对于
Test
的每个实例,方法
testPrint()
不能同时运行。这完全取决于你想做什么。我假设您希望保护
testPrint()
方法,使其不在多个线程中同时运行,同时使用
Test
的多个实例

目前,您直接在方法上使用
synchronized
关键字。这将导致使用对象本身(测试的一个实例)进行同步

您应该在
Test
实例之间共享的另一个对象上进行同步(例如,您可以使锁对象成为静态的)

另外请注意,通常最好只实现
Runnable
接口,然后将实现传递给线程。 另外,您不必每次运行时都创建一个新的
Test
实例(我看不出这样做的目的),我对此进行了注释

public class Test extends Thread {
  // could also use a static monitor instead.
  // private static final Object monitor = new Object();
  private final Object monitor;

  public Test(final Object monitor) {
    this.monitor = monitor;
  }

  public void testPrint() {
    synchronized (monitor) {
      System.out.println("I am sleeping..." + Thread.currentThread().getName());
      try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..." + Thread.currentThread().getName());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void run() {
    //Test t = new Test(monitor);
    //t.testPrint();
    testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
  }

  public static void main(String[] args) {
    // synchronization will happen on this object.
    final Object monitor = new Object();

    Test t1 = new Test(monitor);
    Test t2 = new Test(monitor);

    t1.start();
    t2.start();

  }
}

这里两个线程将进入运行,这将创建两个对象还是一个对象?如果它在两个各自的线程中创建两个对象,我如何在后续代码中使用这两个对象?i、 e.两个对象都有相同的名称“t”!或者范围仅在这些线程中?如果线程共享内存,那么其他线程和主线程应该可以访问这些对象。。那我怎么用呢?如果它只创建一个具有2个引用的对象,那么两个线程不应该同时进入该方法。。正确的?但输出显示的情况并非如此。有两个对象,但没有从其他代码链接到它们。在java中,您不能直接访问内存-您应该将指向对象的链接保存在变量或属性中。当你们将链接保存到变量时,它不能从其他线程访问,当在属性中时,它可以被访问。好的,谢谢,我想我得到了。唯一的问题是,如果我在代码中使用't'对象,那么它将引用哪个对象?由线程1或线程2创建?我如何知道创建了哪些对象,因为对象的状态可能不同。此代码是一个缺陷吗?在您的代码中,您使用了在
current
线程中创建的对象。这不是缺陷本身,它取决于您的目标。两个线程将进入运行,这将创建两个对象还是一个?如果它在两个各自的线程中创建两个对象,我如何在后续代码中使用这两个对象?i、 e.两个对象都有相同的名称“t”!或者范围仅在这些线程中?如果线程共享内存,那么其他线程和主线程应该可以访问这些对象。。那我怎么用呢?如果它只创建一个o