2014-03-25 115 views
2

我只是写了一些代码来测试多线程如何同步,但我无法得到我的预期结果。代码可以启动3个线程,但只有一个线程来处理共享资源。什么是错的用我的代码。java同步多线程问题

class ThreadDemo1{ 
    public static void main (String[] args){ 
     MultiThread tt = new MultiThread(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
    } 
} 
class MultiThread implements Runnable { 
    int tickets = 100; 
    Object _lock = new Object(); 
    public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    synchronized(_lock) { 
     while (true) { 
     if (tickets>0) { 
      try { 
      Thread.sleep(10); 
      } catch (Exception e) {} 
      System.out.println(Thread.currentThread().getName() + " is selling "+tickets--); 
     } 
     } 
    } 
    } 
} 
+0

锁必须是静态 –

+0

你有一些古怪的格式有...采用更标准的格式化会帮你写更清晰的代码,我们理解你的代码。例如,你原来的帖子中遗漏了大括号,这完全不清楚。 – yshavit

回答

2

你正在睡觉,而按住锁。如果你打算这么做,没有理由多线程化。

public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    while(tickets > 0) { 
     synchronized(_lock) { 
      if (tickets > 0) { 
       System.out.println(Thread.currentThread().getName() + " is selling " + tickets--); 
      } 
     } 
     try { 
      Thread.sleep(10); 
     } catch (Exception e) { 
     } 
    } 
} 

我猜0123,是你的处理占位符。如果可能的话,你应该在synchronized块内执行检查和减量操作,但是你需要在它之外进行冗长的处理。

为了使锁和多线程能够为您做任何有用的事情,您必须确保​​代码尽可能少的时间,因为这是一次只能由一个线程运行的代码。

在你的代码中,唯一没有有效单线程的是你的第一个System.println


仅供参考,考虑到这一点,如果你可以让你的打印语句准确,但有可能失灵,这将是更好的有:

public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    while(tickets > 0) { 
     int oldTickets = 0; 
     synchronized(_lock) { 
      if (tickets > 0) { 
       oldTickets = tickets--; 
      } 
     } 
     if(oldTickets > 0) { 
      System.out.println(Thread.currentThread().getName() + " is selling " + oldTickets); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException e) { 
      } 
     } 
    } 
} 
+0

我因为暗示锁定对象变为静态而被骂。也可以将锁对象传递给每个Runnable以同步。我感到不得不防止别人被骂。:) – mttdbrd

+0

@mttdbrd,我的坏。见编辑的答案。 –

0

[1]首先,在您的发布代码中有几个不好的练习/错误:

(1)锁定对象最好是单身。你可以使用一个静态字段对象或类本身(由于只有一个类在存储器中)

Object _lock = new Object(); 
private static final Object _lock = new Object(); 

(2)将while(true) {...}出同步块的。在你的代码中,如果第一个线程获得锁定,它将处理所有票据并且不会停止。 应该让每个线程都尝试在循环的每次迭代中获得Lock。

(3)对于Thread.sleep(10),我想你的意思是线程正在做一些繁重的工作。但将这种代码放入同步块(或另一个名称:关键区域)不是一个好习惯。因为一次只有一个线程可以访问同步块。你的代码行为就像是一个单线程程序,因为其他线程必须等到当前正在运行的线程完成其工作。

请参见下面的代码:

public class ThreadDemo1 { 
    public static void main(String[] args) { 
     MultiThread tt = new MultiThread(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
    } 
} 

public class MultiThread implements Runnable { 
    private static int tickets = 100; 
    private static final Object _lock = new Object(); 

    public void run() { 
     System.out.println(Thread.currentThread().getName()); 
     while (tickets > 0) { 
      try { 
       synchronized (_lock) { 
        if (tickets > 0) { 
         System.out.println(Thread.currentThread().getName() + " is selling " + tickets--); 
        } 
       } 
       Thread.sleep(10); 
      } catch (Exception e) { 
      } 
     } 
    } 
} 

[2]第二,如果你只是想线程在采摘门票同步。尝试使用Atomic*类而不是同步块,它是无锁,并会带来更好的性能。例如:

import java.util.concurrent.atomic.AtomicInteger; 

public class MultiThreadAtomic implements Runnable { 
    private static AtomicInteger tickets = new AtomicInteger(100); 

    public void run() { 
     System.out.println(Thread.currentThread().getName()); 
     int ticketsRemaining = 0; 
     while ((ticketsRemaining = tickets.getAndDecrement()) > 0) { 
      System.out.println(Thread.currentThread().getName() + " is selling " + ticketsRemaining); 
      try { 
       Thread.sleep(10); 
      } 
      catch(InterruptedException ie) {} 
     } 
    } 
}