我试图写一个程序,其中创建了两个线程,输出应该像第一个线程打印1,下一个线程打印2,第一个线程再次打印3,等等。我是一个初学者,所以请帮助我清楚。我认为线程共享相同的内存,所以它们将共享i变量并相应地打印。但是在输出中,我得到了像thread1这样的结果:1、线程2:1、线程1:2、线程2:第二,如此。请帮助.这是我的代码
class me extends Thread
{
public int name,i;
public void run()
{
for(i=1;i<=50;i++)
{
System.out.println("Thread" + name + " : " + i);
try
{
sleep(1000);
}
catch(Exception e)
{
System.out.println("some problem");
}
}
}
}
public class he
{
public static void main(String[] args)
{
me a=new me();
me b=new me();
a.name=1;
b.name=2;
a.start();
b.start();
}
}
3条答案
按热度按时间bt1cpqcv1#
首先,你应该阅读http://www.oracle.com/technetwork/java/codeconventions-135099.html。其次,类成员变量不是共享内存。您需要显式地将一个对象(如计数器)传递给这两个对象,这样它就成为共享的。然而,这仍然不够。共享内存可以被线程缓存,这样你就有了竞争条件。要解决这个问题,您需要使用Lock或AtomicInteger
7d7tgy0s2#
看来你要做的是:
System.out
首先,让我们看看代码中发生了什么:每个号码打印两次。原因是
i
是me
的示例变量,即您的Thread
。因此,每个Thread
都有自己的i
,即它们不共享值。为了使两个线程共享相同的值,我们需要在构造
me
时传递相同的值。现在,用int
原语这样做对我们没有多大帮助,因为通过传递int
,我们没有传递引用,因此两个线程仍然会在独立的内存位置上工作。让我们定义一个新的类
Value
,它为我们保存整数:(**编辑:**同样可以通过传递一个数组int[]
来实现,该数组也包含对其内容的内存位置的引用)现在,
main
可以示例化一个Value
类型的对象,并将对它的引用传递给两个线程。这样,它们就可以访问相同的内存位置。现在
i
不会每次打印两次。但是,您会注意到,该行为仍然没有达到预期的效果。这是因为操作是交错的:a
可以读作i
,假设值是5。接下来,b
递增i
的值,并存储新值。i
现在是6。但是,a
仍然读取了旧值5,并将再次打印5,即使b
刚刚打印了5。为了解决这个问题,我们必须lock示例
v
,即类型为Value
的对象。Java提供了关键字synchronized
,它将在执行synchronized
块内的所有代码时持有锁。但是,如果只是在方法中添加synchronize,仍然无法获得所需的结果。假设你写:第一个线程将获取锁,但在整个循环执行完之前(即
i
的值为50时),永远不会释放它。因此,您必须在安全的情况下以某种方式释放锁。在run
方法中,唯一不依赖于i
(因此不需要锁定)的代码是sleep
,幸运的是,这也是线程花费最多时间的地方。因为所有内容都在循环体中,所以一个简单的
synchronized
块是不行的。我们可以使用Semaphore
来获取锁。因此,我们在main
方法中创建了一个Semaphore
示例,并与v
类似地将其传递给两个线程。然后,我们可以获取并释放Semaphore
上的锁,让两个线程都有机会获得资源,同时保证安全。下面的代码可以实现这一点:
注意:由于我们是在循环结束时获取锁,因此我们也必须在循环结束后释放它,否则资源将永远不会被释放。另外,我将
for
-loop改为while
循环,因为我们需要在第一次释放锁之前更新i
,否则其他线程可以再次读取相同的值。1u4esq0p3#
检查下面的链接的解决方案。使用多个线程,我们可以按升序打印数字
http://cooltekhie.blogspot.in/2017/06/#987628206008590221