繁体   English   中英

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

[英]Can two threads run two different methods at the same point of time?

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

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

如果线程T1正在运行已同步的f(),那么线程T2是否可以在T1仍在运行f()的同时运行未在同一时间同步的g()?

不在同一A实例上。该实例本身是锁,因此如果两个线程同时使用两个线程执行两个方法,则需要两个A实例。

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

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

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

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

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

不会。一个呼叫将阻塞,直到另一个呼叫结束。 这样做的原因是方法上的synced关键字扩展为在对象的当前实例上进行同步。 更具体地说,请考虑以下代码:

private void synchronized f() {
  ...
}

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

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

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

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

如果两个线程都在A的同一实例上执行一个方法,则一次只能执行一个方法。 如果T1首先运行,它将获取A实例的锁,并执行方法f 线程T2将无法执行方法g直到T1完成执行f 否则可能会发生相反的情况:T2可以先运行g ,而T1将在T2完成后才能运行f

正确的答案是重组者的答案。

运行此命令,您将看到。 您还可以通过取消注释/注释样本的相应部分来使用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);
            }
        }
    }
}

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

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

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

当您具有两个相同类的对象时,您将拥有两个锁。 这意味着您可以让两个线程同时运行f()g() ,并且完整保留synchronized关键字,因为这些线程将在不同对象上获取锁。 如果不删除synchronized关键字,就无法使线程在同一对象上同时执行。

对于技术性和pedanticality的利益, 是的 ,这两种方法可以在同一时间进入。 至少在同步(此)上被阻止,但进入方法并正在运行,它的第一条语句正在执行,并且第一条字节码指令已执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM