这是我的代码:
public class TestClass {
public static void main(String[] args) throws Exception {
Thread threadOne = new Thread(new SomeRunnable("x"));
Thread threadTwo = new Thread(new SomeRunnable("y"));
threadOne.start();
threadTwo.start();
}
}
public class SomeRunnable implements Runnable {
private String name;
public SomeRunnable(String name) {
this.name = name;
}
@Override
public void run() {
for(int i=0;i<50;i++) {
NameShouter.shoutName(name);
}
}
}
public class NameShouter {
public static void shoutName(String name) {
synchronized (System.out) {
System.out.print(name);
}
}
}
我将得到的输出是:
xxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
我期待System.out将被同步,但事实并非如此。为什么?我怎样才能使这段代码能够输出:
... XXXXXXXXXXX YYYYYYYY ....
答案 0 :(得分:2)
您正在同步shoutName
的每个调用,这意味着每个名称都在下一个名称之前完全写入。如果你想一个接一个地喊出所有相同的名字,你需要在循环周围移动synchronized
:
public class SomeRunnable implements Runnable {
private String name;
public SomeRunnable(String name) {
this.name = name;
}
@Override
public void run() {
synchronized (System.out) {
for(int i=0;i<50;i++) {
NameShouter.shoutName(name);
}
}
}
}
public class NameShouter {
public static void shoutName(String name) {
System.out.print(name);
}
}
既然你提到你可能有不同的NameShouter
来自不同的东西(并且你仍然需要能够喊出这些名字50次),你可能会引入一个多次喊叫的方法重载,传递PrintStream
以用作参数:
public static void shoutName(String name, int count, PrintStream out) {
synchronized (out) {
out.print(name);
}
}
然后,您只需针对当前行为调用shoutName("x", 50, System.out)
。
随着时间的推移,你会注意到只有静态方法会让事情变得麻烦,你可以使用NameShouter
对象,而这些对象对于他们正在呼喊的资源具有适当的属性以及其他任何必要的对象。
如果您的资源不仅仅是PrintStream
,例如如果你想要将图像的名字大喊大叫,也许,然后在PrintStream
中包装你想要喊出的任何其他东西(可能不是最好的想法,因为滥用某些东西的界面会使它有点难以实现) ,或创建自己的界面,例如
public interface IResource {
void print();
}
并将System.out
以及您正确使用的其他内容包装到IResource
。
答案 1 :(得分:2)
好的尝试这样的事情:
public class TestClass {
public static void main(String[] args) throws Exception {
TestClass test = new TestClass();
Thread threadOne = new Thread(new SomeRunnable("x",test ));
Thread threadTwo = new Thread(new SomeRunnable("y",test ));
threadOne.start();
threadTwo.start();
}
}
public class SomeRunnable implements Runnable {
private String name;
private TestClass test;
public SomeRunnable(String name, TestClass test) {
this.name = name;
this.test = test;
}
@Override
public void run() {
synchronized(test){
for(int i=0;i<50;i++) {
NameShouter.shoutName(name);
}
}
}
}
public class NameShouter {
public static void shoutName(String name) {
System.out.print(name);
}
}
如果您不想创建TestClass对象,可以执行以下操作:
public class Try {
public static void main(String[] args) throws Exception {
Try test = new Try();
Thread threadOne = new Thread(new SomeRunnable("x",Try.class));
Thread threadTwo = new Thread(new SomeRunnable("y",Try.class));
threadOne.start();
threadTwo.start();
}
}
class SomeRunnable implements Runnable {
private String name;
private Class test;
public SomeRunnable(String name, Class test) {
this.name = name;
this.test = test;
}
@Override
public void run() {
synchronized(test){
for(int i=0;i<50;i++) {
NameShouter.shoutName(name);
}
}
}
}