我想测试java多线程,但只运行一个线程

时间:2016-05-08 12:58:29

标签: java

public class ThreadText
{
    public static void main(String[] args)
    {
        windows w=new windows();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);
        Thread t4=new Thread(w);/*four threads*/
        t1.start();
        t2.start();
        t3.start();
        t4.start();
     }
}

我想用四个窗户出售1000张门票

class windows implements Runnable
    {
    int tickets=1000;
    public void run()
    {
    synchronized(this)
    {
        while(tickets>0)
        {
            System.out.println(Thread.currentThread().getName()+" is saling"+tickets);
            tickets--;
        }
    }/*i think problem is here*/    
    }
}

当我不使用synchronized时,所有线程都会运行,但结果是错误的。 一些票号相同。正确的结果是每个窗口都有不同的票号。

感谢

3 个答案:

答案 0 :(得分:1)

当你同步整个循环时,第一个线程将获得锁定并将倒计时为0.其他3个线程将等到第一个线程释放锁定,此时他们没有任何东西可以做。实际上,结果是单线程的。

要正常工作,您需要在循环内部进行同步,以便其他线程也能正常工作。

但是,第一个帖子可能仍然太快,因此它最终会完成所有工作。为了更好地模拟您想要的内容,请在同步块之外添加延迟(使销售需要时间,您知道)。在下面的代码中添加了1ms的最小延迟。

最后,Java命名约定是以类型名称开头的大写字母,因此应将其命名为Windows

class Windows implements Runnable {
    private int tickets = 1000;
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        for (;;) { // loop forever
            synchronized (this){
                if (this.tickets == 0)
                    break;
                System.out.println(threadName + " is saling " + this.tickets);
                this.tickets--;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}

<强>输出

Thread-0 is saling 1000
Thread-2 is saling 999
Thread-3 is saling 998
Thread-1 is saling 997
Thread-0 is saling 996
Thread-1 is saling 995
Thread-2 is saling 994
Thread-3 is saling 993
Thread-0 is saling 992
Thread-1 is saling 991
Thread-3 is saling 990
Thread-2 is saling 989
        . . .
Thread-2 is saling 11
Thread-1 is saling 10
Thread-0 is saling 9
Thread-3 is saling 8
Thread-0 is saling 7
Thread-1 is saling 6
Thread-2 is saling 5
Thread-1 is saling 4
Thread-0 is saling 3
Thread-3 is saling 2
Thread-2 is saling 1

答案 1 :(得分:0)

您遇到的情况称为竞争条件。这意味着由于线程的运行顺序,你可以得到两个线程,认为它们减少了一些东西,但只有一个做了,等等。

要解决此问题,您有两种选择:

  • synchronized - 这是非常沉重的,除非你把它放在最小的临界区,否则会太多。
  • page - 确保整数在线程间安全递增或递减。

要修复您的示例并仍使用synchronized,您的代码应如下所示:

class windows implements Runnable
{
    int tickets=1000;
    public void run()
    {
        while(tickets>0)
        {
            synchronized(this)
            {
                System.out.println(Thread.currentThread().getName()+" is saling"+tickets);
                tickets--;
            }
         }
     }
 }

当然,缺点是你需要记住synchronize对变量的所有访问权限。

使用AtomicInteger过程更容易控制:

class windows implements Runnable
{
    AtomicInteger tickets = new AtomicInteger(1000);
    public void run()
    {
        while(tickets.get() > 0)
        {
            System.out.println(Thread.currentThread().getName()
                + " is saling" + tickets.decrementAndGet());
         }
     }
 }

答案 2 :(得分:0)

由于多个线程访问的票证成员,您需要进行同步。但是因为你在基于门票的基础上运行run方法&gt; 0,只有1个线程将一直运行到结束。一种解决方案是将线程的执行与另一个变量联系起来,让run方法只减少一次票证,然后休眠,这样其他线程就有机会运行。例如,如果您按如下方式重构Windows类,那么它将执行我认为您希望它执行的操作。

class windows implements Runnable {
    volatile boolean finished = false;
    int tickets = 1000;

    public void run() {
        while(!finished) {
            synchronized(this) {
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName()+" is selling " + tickets);
                    tickets--;

                    if (tickets <= 0) {
                        finished = true;
                    }
                }
            }
            try {
                Thread.sleep(10);
            }
            catch(InterruptedException ex) {
            }
        }
    }
}