两个线程可以在同一时间点运行两种不同的方法吗?

时间:2010-09-07 19:38:45

标签: java multithreading

class A {
    private synchronized f() {
        ...
        ...
    }

    private void g() {
        ...
        ...
    }
}

如果线程T1正在运行同步的f(),那么线程t2可以运行g(),它在同一时间点不同步,而T1仍在运行f()吗?

7 个答案:

答案 0 :(得分:16)

不在同一个A实例上。实例本身就是锁,所以两个方法同时执行两个方法,两个线程需要两个A实例。

答案 1 :(得分:6)

是。两种方法都可以在同一个实例上同时执行。

仅同步f()。线程必须获取this.f()的监视器才能执行f(),并且每个实例只存在一个监视器。

g()未同步,运行该方法不需要监视器锁定,因此任何线程都可以随时执行g()

“同步方法在执行之前获取监视器(第17.1节)。”

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.3.6

答案 2 :(得分:4)

没有。一个呼叫将阻塞,直到另一个完成。原因是方法上的synchronized关键字扩展为在对象的当前实例上同步。更具体地说,请考虑以下代码:

private void synchronized f() {
  ...
}

以上代码的功能与以下代码相同:

private void f() {
  synchronized (this) {
    ...
  }
}

因此,如果您希望对象中的两个方法仅相互同步,则应创建两个锁定对象。每个方法都应将其所有代码包装在同步(对象)块中,每个方法都有一个对象。

答案 3 :(得分:3)

是的,如果T1和T2分别在A的不同实例上执行fg

如果两个线程在同一个A实例上执行方法,则一次只能执行一个方法。如果T1先运行,它将获取A实例的锁定,并执行方法f。在T1完成执行g之前,线程T2将无法执行方法f。或者相反的情况可能发生:T2可以先运行g,T1在T2完成之后将无法运行f

答案 4 :(得分:2)

通常,两个线程可以在同一时间点运行两个方法;但是,在您的示例中,在任何给定时刻,只有一个线程可能正在运行f()g()

使用synchronized关键字更改线程交互。每个java对象都有一个锁,一个只有一个线程可以在任何给定时间保存的项。 Synchronized是一个命令,它指示线程在执行方法之前获取锁,然后释放它。在整个方法执行期间保持锁定。

在您的示例中,在任何给定时间只有一个线程将执行f()g(),因为“其他”线程将轮流等待获取锁定。

当你有两个同一个类的对象时,你有两个锁。这意味着你可以让两个线程同时运行f()g() synchronized关键字,因为线程将抓取不同对象的锁。如果不删除synchronized关键字,您就无法在同一对象上同时执行线程。

答案 5 :(得分:2)

对此的正确答案是重新组装者的答案。

运行这个,你会看到。您还可以通过取消注释/注释样本的相应部分来使用Thread.sleep()而不是无限循环进行测试。

如果代码没有遵循最佳实践,我很抱歉,我的java非常生疏。

package threadtest;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ThreadTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        TestClass tc = new TestClass();

        // invokes not sync method
        FirstThreadRunnable ftr = new FirstThreadRunnable(tc);
        Thread t1 = new Thread(ftr);

        // invokes the sync method
        SecondThreadRunnable str = new SecondThreadRunnable(tc);
        Thread t2 = new Thread(str);

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


        System.in.read();
    }

    public static class TestClass {

        private int callCount = 0;

        public void notSynchronizedMethod() {
            System.out.println("notSynchronizedMethod says hello!" + " [" + callCount++ +"] from thread: " + Thread.currentThread().getId());
        }

        public synchronized void synchronizedMethod() throws InterruptedException {
            // Test with the sleep
            //System.out.println("entering sync method and pausing from thread: " + Thread.currentThread().getId());
            //Thread.sleep(5000); // hold the monitor for 5sec
            //System.out.println("exiting sync method"  + " [" + callCount++ +"] from thread: " + Thread.currentThread().getId());

            // Test with spinning
            System.out.println("MAKE IT SPIN! from thread: " + Thread.currentThread().getId());
            boolean spin = true;
            while(spin){

            }
            System.out.println("IT STOPPED SPINNING! from thread: " + Thread.currentThread().getId());
        }
    }

    // invokes the not sync method
    public static class FirstThreadRunnable implements Runnable {
        TestClass tester = null;
        public FirstThreadRunnable(TestClass tester){
            this.tester = tester;
        }


        @Override
        public void run() {
            for(int i = 0; i < 500; i++){
                tester.notSynchronizedMethod();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }

    // invokes the sync method
    public static class SecondThreadRunnable implements Runnable {

        TestClass tester = null;
        public SecondThreadRunnable(TestClass tester){
            this.tester = tester;
        }

        @Override
        public void run() {
            try {
                // Test with Sleep()
                //for(int i = 0; i < 5; i++){
                //  tester.synchronizedMethod();
                //}

                // Test with the spinning
                tester.synchronizedMethod();

            } catch (InterruptedException ex) {
                Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

答案 6 :(得分:0)

为了技术性和迂腐的兴趣,,两种方法可以同时输入。一个在synchronized(this)上被阻塞,非常少,方法进入并运行,它的第一个语句正在执行,并且执行了第一个字节代码指令。