java同步多线程问题

时间:2014-03-25 00:16:16

标签: java multithreading synchronized

我只是编写了一些代码来测试多个线程如何同步,但我无法得到我预期的结果。代码可以启动3个线程,但只有一个线程来处理共享资源。我的代码出错了。< / p>

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--);
        }
      }
    }
  }
}

2 个答案:

答案 0 :(得分: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) {
        }
    }
}

我猜测sleep是您处理的占位符。如果可能的话,你应该在synchronized块中进行检查和减量,但是在它之外进行冗长的处理。

为了使锁和多线程能够对你做任何有用的事情,你必须确保你的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) {
            }
        }
    }
}

答案 1 :(得分:0)

[1]首先,您发布的代码中存在一些不良做法/错误:

(1)锁定对象是单身的更好。您可以使用静态字段对象或类本身(因为内存中只有一个类)

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

(2)将while(true) {...}放出同步块。在您的代码中,如果第一个线程获得Lock,它将处理所有票证并且不会停止。 应该让每个线程尝试在循环的每次迭代中获得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*类而不是synchronized块,它是No-lock并且会为您带来更好的性能。例如:

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) {}
        }
    }
}