【问题标题】:Not being able to synchronize method in java无法在java中同步方法
【发布时间】:2013-11-24 19:04:33
【问题描述】:

我想了解下面java中的线程同步是代码有一个名为Interview的主类。在那个类中,我正在创建两个对象

public class Interview{

    /**
     * @param args the command line arguments
     * @throws java.lang.InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO code application logic here\
        Race r1=new Race();
        r1.setA(15);
        Thread t1=new Thread(r1, "First thread");
        Race r2=new Race();
        r2.setA(25);

        Thread t2=new Thread(r2, "Second thread");
        t1.start();
        t2.start();
        }
}

还有其他类具有名为 Race 的 run 方法,这里是代码

public class Race implements Runnable{
    int a;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }
    @Override
    public void run() {
        try {

                print();



        } catch (InterruptedException ex) {
            Logger.getLogger(Race.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
   public synchronized void print() throws InterruptedException{
       for(int i=1;i<=10;i++){
           System.out.println(a*i);
           Thread.sleep(1000);
       }

   }
}

对于每个对象,我给出不同的 a 值,然后尝试同步打印方法,但它不起作用。我使用的概念是两个试图同时访问分片资源的线程不能通过使用同步方法来做到这一点。因此,在我的情况下,两个线程 t1 和 t2 试图同时访问 print 方法,所以我将 synchronized 关键字与 print 方法一起使用,但结果仍然相同。我想要的是线程 t1 首先执行,即15 30 45 60..... 然后螺纹 t2 即 25 50 75... 等等。 如果我的概念不清楚,请纠正我..

【问题讨论】:

  • 方法不是共享资源!共享资源只能是类对象的字段。在您的示例中,没有共享资源,因为两个 Race 实例都有自己的字段 a。

标签: java multithreading synchronization synchronized


【解决方案1】:

您的同步方法是一个实例方法。这意味着为同步而获得的锁是通过实例本身获得的。因此,当您的线程运行时,一个获得对 r1 的锁定,另一个获得对 r2 的锁定。因此,它运行良好,只是不是您所期望的。

您似乎想在 r1 和 r2 之间创建互斥。为此,您的方法需要是静态的,以便在类对象上获得锁。或者您需要使用两个线程共享的不同锁定对象(仅基于您的示例看起来没有必要)。

换句话说,您的线程不共享同一个对象,因此它们之间没有任何竞争条件。

例如,您可以通过让两个线程使用同一个 Race 实例或创建一个由两者共享的互斥对象来创建互斥。

像这样:

class Race {
  public void synchronized print(){
    ...
  }
}

Race r = new Race();
Thread t1 = new Thread(r); 
Thread t2 = new Thread(r); //notice both threads share r.

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

在上面的例子中,两个线程都会尝试在同一个对象上运行 print 方法。这意味着,synchornized 关键字在这里创建了一个互斥块。当时只有一个线程可以获得对竞赛对象的锁定。

如果您使用两个不同的 Race 实例,那么创建互斥是没有意义的。由于没有竞争条件,因此使线程相互协调没有意义。那只会毫无必要地拖延他们。

【讨论】:

  • 如果我将方法设为静态,那么我将无法访问变量,因为它不是静态的,除了静态方法之外,我还能做些什么来获得类的锁定。你说不同的锁怎么可能
  • @RiteshSangwan 让两个线程使用相同的Race 对象。或者让他们共享一些其他对象,您可以在这些对象上执行synchronized(lock){ ... } 之类的操作
  • OKk 现在我理解了这个概念,但是如果我使用相同的竞赛类实例,如何为两个线程单独设置 A。
  • @RiteshSangwan 重点是,如果您需要使用两个不同的 Race 实例,则不存在竞争条件。两个线程没有理由不能在两个独立对象上并行操作。如果这就是您所需要的,那么您根本不需要同步。另一方面,如果需要共享同一个对象,则需要处理同步。那么,你的场景是什么?
  • 明白了....正是我想要的。在比赛类中,我检查了线程的名称,然后相应地初始化了一个。
【解决方案2】:

规则实际上是在同一个对象上同步的两个方法不能同时运行。

声明为同步的非静态方法在其对象上同步,因此每个 Race 中的 print() 方法在其自己的 Race 对象上同步。

您可以声明一个同步块,其中包含在共享对象(例如 Race.class)上同步的方法体。

【讨论】:

    【解决方案3】:
    public class Race implements Runnable {
        private final Object lock;
    
        public Race(Object lock) {
            this.lock = lock;
        }
    
        @Override
        public void run() {
            try {
                print();
            } catch (InterruptedException ex) {
                Logger.getLogger(Race.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    
        public void print() throws InterruptedException {
            synchronized(lock) {
                for(int i = 1; i <= 10; i++){
                    System.out.println(i);
                    Thread.sleep(1000);
                }
            }
        }
    }
    
    public class Interview{
        public static void main(String[] args) throws InterruptedException {
            Object lock = new Object();
    
            Race r1 = new Race(lock); // <== lock object
            Thread t1 = new Thread(r1, "First thread");
    
            Race r2 = new Race(lock); // <== same lock object
            Thread t2 = new Thread(r2, "Second thread");
    
            t1.start();
            t2.start();
        }
    }
    

    【讨论】:

      【解决方案4】:

      不能保证先执行哪个线程。由JVM决定哪个线程先开始。正如您所说的What I want is thread t1 to execute first i,e. 15 30 45 60..... then thread t2 i.e, 25 50 75... and so on,您可以使用join() 方法。它将确保只有在加入它的线程完成后才会执行其他线程。更多信息请参考this

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-08
        • 1970-01-01
        • 2011-11-08
        • 2013-02-28
        • 2014-07-11
        相关资源
        最近更新 更多