java:同步方法效率低下

标签 java multithreading synchronization synchronized thread-synchronization

我正在经历这个程序,但不太明白它的意义。

    class Q
  {
     int n;
    synchronized int get()
   { 
    System.out.println("Got: " + n); 
    return n;
   }
    synchronized void put(int n)
   { 
   this.n = n; 
   System.out.println("Put: " + n);
 } 
}
  class Producer implements Runnable 
{ 
Q q;
Producer(Q q) 
{
 this.q = q;
 new Thread(this, "Producer").start(); }
public void run() 
{
 int i = 0;
 while(true) 
{ q.put(i++); }
}
}
class Consumer implements Runnable 
{
 Q q;
Consumer(Q q)
 { 
 this.q = q; new Thread(this, "Consumer").start();
 }
public void run() { while(true) { q.get(); } }
}
class PC 
{
public static void main(String args[]) 

{ 
     Q q = new Q(); 
     new Producer(q); 
      new Consumer(q);

System.out.println("Press Control-C to stop.");
}
}

虽然 Q 上的 put() 和 get() 方法是同步的,但没有什么可以阻止生产者超出消费者的范围,也没有什么可以阻止消费者两次使用相同的队列值。因此,您会得到如下所示的错误输出:

放置:1 获得:1 获得:1 获得:1 获得:1 获得:1 投入:2 投入:3 投入:4 投入:5 投入:6 看跌:7 获得:7

正如你所看到的,生产者放入1后,消费者启动并连续五次获得相同的1。然后,生产者恢复并生产2到7,而不让消费者有机会消费它们。问题是为什么我们会得到如此奇怪的输出,我的意思是,当执行 get() 时,它会返回一个值,然后线程应该从监视器退出,而不是停留在那里并打印 1 多次,并且;然后 put() ,它如何能够递增并打印这些值。 ???请帮忙,我知道我可能显得很幼稚,因为我是java新手。

最佳答案

操作系统调度程序决定执行哪个线程以及哪个线程获得锁。它不必在线程之间针锋相对地交替,它只是确保没有任何东西会因为缺少 cpu 片而饿死。正如您所看到的,一个线程运行了一段时间,然后另一个线程获得了机会。让线程拥有一段时间的通行权可能有助于最大限度地减少上下文切换。每次调度程序切换正在运行的线程都会产生开销,最好让线程有机会运行并完成某些任务,而不是在它们之间颠簸。

如果您希望线程严格交替工作,那么您可以通过让线程等待直到 Q 处于有效状态来强制执行:

class Q {
    Integer n; // nullable
    public synchronized int get() {
        while (n == null) {
            wait();
        }
        notifyAll();
        System.out.println("got: " + n);
        int retval = n;
        n = null;
        return retval;
    }
    public synchronized void put(int n) {
        while (n != null) {
            wait();
        }
        notifyAll();
        this.n = n;
        System.out.println("put: " + n);
    }
}

这个版本的 Q 将导致两个线程轮流。

如果您只想让线程放置和设置值而不交替,那么使用 AtomicInteger 会更简单。同步是为了组合多个 Action ,这样它们就不会被其他线程干扰。

关于java:同步方法效率低下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43671005/

相关文章:

java - 递归函数不能与 try/catch 一起使用吗?

c++ - 为什么多线程循环不是更快?

c# - APM 模式使用线程池中的线程?

java - AtomicBoolean vs Synchronized block ,有什么区别

java - 通用图像加载器,下载更高效,数据更少。如何?

java - 使用 JDT 从方法开始深入访问所有方法调用

multithreading - 使用 MVar 在 Haskell 中创建线程安全队列(也许?)

.net - ReaderWriterLockSlim : acquiring a read lock after an upgradeable lock doesn't throw LockRecursionException

Java同步

java.lang.Object 无法转换