java同步多线程问题

java同步多线程问题,java,multithreading,synchronized,Java,Multithreading,Synchronized,我只是写了一些代码来测试多线程如何同步,但我无法得到预期的结果。代码可以启动3个线程,但只有一个线程来处理共享资源。我的代码有什么问题 class ThreadDemo1{ public static void main (String[] args){ MultiThread tt = new MultiThread(); new Thread(tt).start(); new Thread(tt).start(); new Thr

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

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

你拿着锁睡觉。如果要这样做,就没有理由使用多线程

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) {
        }
    }
}
我猜
睡眠
是您处理的占位符。如果可能,您应该在同步块内执行检查和减量操作,但在同步块外执行冗长的处理

为了让锁和多线程对您有用,您必须确保
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]首先,在您发布的代码中有几个不好的做法/错误:

(1) 最好将Lock对象设置为singleton。您可以使用静态字段对象或类本身(因为内存中只有一个类)

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

(3) 对于
线程.sleep(10)
,我猜您的意思是线程正在做一些繁重的工作。但将此类代码放在同步块(或另一个名称:critical region)中并不是一个好的做法。因为一次只有一个线程可以访问同步块。代码的行为类似于单线程程序,因为其他线程必须等待当前运行的线程完成其任务

请参见以下代码:

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 block,它是无锁的,将为您带来更好的性能。例如:

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

锁必须是静态的你有一些奇怪的格式。。。采用更标准的格式将有助于您编写更清晰的代码,并让我们理解您的代码。例如,你在原来的帖子中根本不清楚是否缺少右大括号,我因为建议将锁对象设为静态对象而被责骂。还可以将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) {}
        }
    }
}