【问题标题】:Why my synchronized method not working properly?为什么我的同步方法不能正常工作?
【发布时间】:2018-07-02 05:31:03
【问题描述】:

我有这个打印计数器的同步方法,我有 4 个线程,所以我希望我的计数器的最终值为 400000,因为我的计数器是一个静态变量。

但是每次我运行我的代码时,它都会给我不同的计数器值。

以下是我的代码:

class MyThread implements Runnable{

    private static int counter=1;
    @Override
    public void run() {
        try {
            this.syncMethod();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public synchronized void syncMethod() throws InterruptedException{
        for(int i=0;i<100000;i++){
            System.out.println(Thread.currentThread().getName()+" : "+counter++);
        }
    }
}

public class MyController {
    public static void main(String[] args) throws InterruptedException {
        Runnable r1=new MyThread();
        Runnable r2=new MyThread();
        Runnable r3=new MyThread();
        Runnable r4=new MyThread();
        Thread t1;
        Thread t2;
        Thread t3;
        Thread t4;
        t1=new Thread(r1,"Thread 1");
        t2=new Thread(r2,"Thread 2");
        t3=new Thread(r3,"Thread 3");
        t4=new Thread(r4,"Thread 4");

        t2.start();
        t1.start();
        t3.start();
        t4.start();
    }
}

【问题讨论】:

    标签: java multithreading synchronized synchronized-block


    【解决方案1】:

    变量是static,但是你synchronized的方法不是static。这意味着它将获取当前实例上的监视器,并且每个线程都有不同的当前实例。

    一个简单的解决方案是将syncMethod方法也设为static;在这种情况下,它将锁定由MyThread 类的所有实例共享的监视器:

    public static synchronized void syncMethod()
    

    【讨论】:

    • 谢谢,您的解决方案有效,我还发现如果我通过相同的 Runnable 实例 ex。 r1 到所有 4 个线程实例(新线程(r1,“线程 4”))然后我的代码也可以在没有声明我的方法静态的情况下工作
    • @Akshay 是的,如果您传递相同的实例,它无需制作方法 static 即可工作。然而,在这种情况下,甚至没有必要将变量设为静态。您可以将其删除,并且在您同步该方法时它也应该可以工作。
    【解决方案2】:

    Erwin Bolwidt 的回答对解决您的问题是正确的。作为在多个线程中安全地增加静态共享计数器的另一种方法,您可以求助于AtomicLong

    定义如下:

    private static AtomicLong counter = new AtomicLong();
    

    将其递增为:

    counter.getAndIncrement();
    

    最后得到结果:

    counter.get();
    

    【讨论】:

      【解决方案3】:

      非静态方法中的同步关键字意味着与此方法完全同步:这两个代码严格等效:

      public synchronised void dojob(){
           //the job to do 
      }
      

      public void dojob(){
           synchronised (this){
           //the job to do 
           }
      }
      

      在您的情况下,您的同步方法在不同的对象(t1、t2、t3 和 t4)上同步,所以不要互相阻止它们。最好的解决方案是你的线程将使用一个公共对象来相互同步。另一点,最好让它的线程回来做这个调用加入这里是一个代码来做你想做的这两个修复

      class MyThread implements Runnable {
      
          public static class JobDoer {
      
              public synchronized void syncMethod() throws InterruptedException {
                  for (int i = 0; i < 100000; i++) {
                      System.out.println(Thread.currentThread().getName() + " : " + counter++);
                  }
              }
          }
      
          private static int counter = 1;
      
          public MyThread(JobDoer doer) {
              this.doer = doer;
          }
      
          private JobDoer doer;
      
          @Override
          public void run() {
              try {
                  doer.syncMethod();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          public static void main(String[] args) throws InterruptedException {
              JobDoer doer = new JobDoer();
              Thread t1 = new Thread(new MyThread(doer), "Thread 1");
              Thread t2 = new Thread(new MyThread(doer), "Thread 2");
              Thread t3 = new Thread(new MyThread(doer), "Thread 3");
              Thread t4 = new Thread(new MyThread(doer), "Thread 4");
      
              t2.start();
              t1.start();
              t3.start();
              t4.start();
              t1.join();
              t2.join();
              t3.join();
              t4.join();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-02-06
        • 2013-05-21
        • 2020-11-17
        • 1970-01-01
        • 2020-03-28
        • 1970-01-01
        • 2021-09-01
        • 1970-01-01
        • 2016-01-30
        相关资源
        最近更新 更多