java 多线程程序打印数字从1到50?

cigdeys3  于 2023-06-20  发布在  Java
关注(0)|答案(3)|浏览(135)

我试图写一个程序,其中创建了两个线程,输出应该像第一个线程打印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();
}
}
bt1cpqcv

bt1cpqcv1#

首先,你应该阅读http://www.oracle.com/technetwork/java/codeconventions-135099.html。其次,类成员变量不是共享内存。您需要显式地将一个对象(如计数器)传递给这两个对象,这样它就成为共享的。然而,这仍然不够。共享内存可以被线程缓存,这样你就有了竞争条件。要解决这个问题,您需要使用LockAtomicInteger

7d7tgy0s

7d7tgy0s2#

看来你要做的是:

  • 将从1到50的所有数字写入System.out
  • 而不需要多次打印任何数字
  • 数字按顺序打印
  • 让两个并发线程执行此操作

首先,让我们看看代码中发生了什么:每个号码打印两次。原因是ime的示例变量,即您的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。
为了解决这个问题,我们必须lock示例v,即类型为Value的对象。Java提供了关键字synchronized,它将在执行synchronized块内的所有代码时持有锁。但是,如果只是在方法中添加synchronize,仍然无法获得所需的结果。假设你写:

public void run(){ synchronized(v) {
  for(; v.i < 50; v.i++) {
  // ...
}}

第一个线程将获取锁,但在整个循环执行完之前(即i的值为50时),永远不会释放它。因此,您必须在安全的情况下以某种方式释放锁。在run方法中,唯一不依赖于i(因此不需要锁定)的代码是sleep,幸运的是,这也是线程花费最多时间的地方。
因为所有内容都在循环体中,所以一个简单的synchronized块是不行的。我们可以使用Semaphore来获取锁。因此,我们在main方法中创建了一个Semaphore示例,并与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-loop改为while循环,因为我们需要在第一次释放锁之前更新i,否则其他线程可以再次读取相同的值。

1u4esq0p

1u4esq0p3#

检查下面的链接的解决方案。使用多个线程,我们可以按升序打印数字
http://cooltekhie.blogspot.in/2017/06/#987628206008590221

相关问题