synchronized keyword is giving the expected output but not satisfied with the order in which the method is called by different threads

huangapple go评论83阅读模式
英文:

synchronized keyword is giving the expected output but not satisfied with the order in which the method is called by different threads

问题

以下是实现了Runnable接口的三个类(线程)的代码部分:

public class Thread1 implements Runnable {
    Shared s;

    public Thread1(Shared s){
        this.s = s;
    }

    @Override
    public void run() {
        System.out.println("Sum of 10 and 20 by " + Thread.currentThread().getName() + " is " + s.add(10, 20));
    }
}

public class Thread2 implements Runnable {
    Shared s;

    public Thread2(Shared s){
        this.s = s;
    }

    @Override
    public void run() {
        System.out.println("Sum of 100 and 200 by " + Thread.currentThread().getName() + " is " + s.add(100, 200));
    }
}

public class Thread3 implements Runnable {
    Shared s;

    public Thread3(Shared s){
        this.s = s;
    }

    @Override
    public void run() {
        System.out.println("Sum of 1000 and 2000 by " + Thread.currentThread().getName() + " is " + s.add(1000, 2000));
    }
}

以下是被这些线程共享的对象类的代码部分:

public class Shared {
    private int x;
    private int y;

    synchronized public int add(int a, int b) {
        x = a;
        y = b;

        try {
            System.out.println(Thread.currentThread().getName() + " is going into sleep state");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return x + y;
    }
}

最后,以下是如何启动线程并传递Shared对象的代码部分:

public static void main(String[] args) {
    Shared s = new Shared();
    Thread t1 = new Thread(new Thread1(s), "Thread-1");
    Thread t2 = new Thread(new Thread2(s), "Thread-2");
    Thread t3 = new Thread(new Thread3(s), "Thread-3");

    t1.start();
    t2.start();
    t3.start();
}

请注意,我只提供了代码的翻译部分,没有包含其他内容。

英文:

Below are my 3 classes(threads) implementing Runnable interface:

public class Thread1 implements Runnable {
Shared s;

public Thread1(Shared s){
	this.s = s;
}

@Override	
public void run() {
	System.out.println("Sum of 10 and 20 by " + Thread.currentThread().getName() + " is "+ s.add(10, 20));
}

}

public class Thread2 implements Runnable {
Shared s;

public Thread2(Shared s){
	this.s = s;
}
	
@Override
public void run() {
	System.out.println("Sum of 100 and 200 by " + Thread.currentThread().getName() + " is " + s.add(100, 200));
}

}

public class Thread3 implements Runnable {
Shared s;

public Thread3(Shared s){
	this.s = s;
}
	
@Override
public void run() {
	System.out.println("Sum of 1000 and 2000 by " + Thread.currentThread().getName() + " is " + s.add(1000, 2000));
}

}

And below is the class whose object is shared among these threads:

public class Shared {
private int x;
private int y;

synchronized public int add(int a, int b) {
	x = a;
	y = b;

	try {
		System.out.println(Thread.currentThread().getName() + "is going into sleep state");
		Thread.sleep(1000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	return x + y;
}

}

And finally this is how I'm starting threads and passing Shared object:

    public static void main(String[] args) {
	Shared s = new Shared();
	Thread t1 = new Thread(new Thread1(s), "Thread-1");
	Thread t2 = new Thread(new Thread2(s), "Thread-2");
	Thread t3 = new Thread(new Thread3(s), "Thread-3");
	
	t1.start();
	t2.start();
	t3.start();
}

This is the output I'm getting which is correct:

      Thread-2is going into sleep state
      Thread-1is going into sleep state
      Sum of 100 and 200 by Thread-2 is 300
      Thread-3is going into sleep state
      Sum of 10 and 20 by Thread-1 is 30
      Sum of 1000 and 2000 by Thread-3 is 3000

But if you see here, Thread-1 started executing the add method(which is synchronized) before Thread-2 finished its job.
Since Thread-2 went into sleep state so it also took the lock with itself and no other thread should be allowed to enter the add(...) method. Thread-1 or Thread-3 could only start executing add(...) method after Thread-2 is done. So, the output I was expecting was :

      Thread-2is going into sleep state
      Sum of 100 and 200 by Thread-2 is 300
      Thread-1is going into sleep state
      Sum of 10 and 20 by Thread-1 is 30
      Thread-3is going into sleep state
      Sum of 1000 and 2000 by Thread-3 is 3000

Please tell what I'm doing wrong or this is how the output will be, if yes, please tell why.

答案1

得分: 2

以下是翻译好的部分:

原因是 System.out.println() 很慢。

您在 run() 方法内部以及 add() 方法内部都使用它发送消息。不能保证 sysout 中的消息一致。

我已经重写了 Shared 如下:

public class Shared {
	private int x;
	private int y;

	synchronized public int add(int a, int b) {
		x = a;
		y = b;

		try {
			long now = System.currentTimeMillis() - start;

			Thread.sleep(1000);

			// 注意先是 sleep,然后是 sysout
			System.out.println(Thread.currentThread().getName() + " 计算发生在时间 " + now);

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return x + y;
	}

	public static long start;

	public static void main(String[] args) {

		start = System.currentTimeMillis();

		Shared s = new Shared();
		Thread t1 = new Thread(new Thread1(s), "Thread-1");
		Thread t2 = new Thread(new Thread2(s), "Thread-2");
		Thread t3 = new Thread(new Thread3(s), "Thread-3");

		t1.start();
		t2.start();
		t3.start();
	}
}

现在每个线程看起来如下:

public class Thread1 implements Runnable {
	Shared s;

	public Thread1(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		int result = s.add(10, 20);
		long now= System.currentTimeMillis()-Shared.start;
		System.out.println(Thread.currentThread().getName() + " 计算 10 和 20 的总和为 " + result+ ",发生在 "+ now);
	}
}

生成以下输出:

Thread-1 计算发生在时间 2
Thread-1 计算 10 和 20 的总和为 30,发生在 1005
Thread-2 计算发生在时间 1005
Thread-2 计算 100 和 200 的总和为 300,发生在 2006
Thread-3 计算发生在时间 2006
Thread-3 计算 1000 和 2000 的总和为 3000,发生在 3007

每个线程都在 add() 中被阻塞,只有在稍后显示结果时,下一个线程才开始计算。

请注意,现在 add() 中首先是 sysout(这很慢),而且它发生在睡眠期间,这给了它足够的时间。

英文:

The reason is that the System.out.println() is very slow.

You use it to send messages from both within the run() methods and also from within add(). There is no guarantee that the messages in sysout coincide.

I have rewritten Shared as follows:

public class Shared {
	private int x;
	private int y;

	synchronized public int add(int a, int b) {
		x = a;
		y = b;

		try {
			long now = System.currentTimeMillis() - start;

			Thread.sleep(1000);

			// notice FIRST sleep and THEN sysout
			System.out.println(Thread.currentThread().getName() + " calculation has taken place at time " + now);

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return x + y;
	}

	public static long start;

	public static void main(String[] args) {

		start = System.currentTimeMillis();

		Shared s = new Shared();
		Thread t1 = new Thread(new Thread1(s), "Thread-1");
		Thread t2 = new Thread(new Thread2(s), "Thread-2");
		Thread t3 = new Thread(new Thread3(s), "Thread-3");

		t1.start();
		t2.start();
		t3.start();
	}
}

with each of the threads now looking like:

public class Thread1 implements Runnable {
	Shared s;

	public Thread1(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		int result = s.add(10, 20);
		long now= System.currentTimeMillis()-Shared.start;
		System.out.println("Sum of 10 and 20 by " + Thread.currentThread().getName() + " is " + result+ " found at "+ now);
	}
}

generating the following output:

Thread-1 calculation has taken place at time 2
Sum of 10 and 20 by Thread-1 is 30 found at 1005
Thread-2 calculation has taken place at time 1005
Sum of 100 and 200 by Thread-2 is 300 found at 2006
Thread-3 calculation has taken place at time 2006
Sum of 1000 and 2000 by Thread-3 is 3000 found at 3007

each thread blocked in add() as it should.

Only when later the result is displayed, the next thread has already started calculating.

Notice that add() now there is first the sysout (which is slow) and it happens during the sleep, which gives it enough time.

答案2

得分: 1

您需要按照以下方式同步 `s`:

@Override
public void run() {
    synchronized (s) {
        System.out.println("Sum of 10 and 20 by " + Thread.currentThread().getName() + " is " + s.add(10, 20));
    }
}

Thread2Thread3 类中也要这样做。查看 此链接 以获取解释。

英文:

You need to synchronize s as shown below:

@Override
public void run() {
	synchronized (s) {
		System.out.println("Sum of 10 and 20 by " + Thread.currentThread().getName() + " is " + s.add(10, 20));
	}
}

Do this in the classes, Thread2 and Thread3 as well. Check this for an explanation.

huangapple
  • 本文由 发表于 2020年8月4日 03:44:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63235994.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定