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();
}
}
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时,所有线程都会运行,但结果是错误的。 一些票号相同。正确的结果是每个窗口都有不同的票号。
答案 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
- 这是非常沉重的,除非你把它放在最小的临界区,否则会太多。要修复您的示例并仍使用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) {
}
}
}
}