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