我正在学习java认证,我从Mughal的书中看到了这个例子:
public class Smiley extends Thread
{
@Override
public void run()
{
while(true)
{
synchronized(this)
{
try
{
System.out.print(":");
Thread.sleep(100);
System.out.print("-");
Thread.sleep(100);
System.out.println(")");
Thread.sleep(100);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
public static void main(String[] args)
{
new Smiley().start();
new Smiley().start();
}
}
目的是每行打印一个笑脸:-)。我的问题是,为什么同步实例(这个)不能实现这一点?为什么我们需要在静态级别上进行同步?
谢谢,
答案 0 :(得分:6)
因为请注意main()函数会创建两个 Smiley类。他们每个人都在自己的线程上运行。由于它们锁定this
,它们都将立即获得锁定,而不会与另一个线程发生争用。在这种情况下,synchronize(this)
的锁定方案完成任何事情。
在处理多线程问题时,您必须考虑“我想保护什么?”在这种情况下,您需要保护System.out
,以确保您正在访问它按照你想要的顺序。由于System.out
是静态的,因此您需要某种外部作用域锁定,每个线程必须先获取它们才能写入。
您可以使用ReentrantLock来实现此目标。
答案 1 :(得分:2)
请不要使用synchronized(this) - 这一般是不好的做法
如上所述 - 锁应该在两个线程之间共享,在这种情况下,锁是每个类的实例(即 - 由新的Smiley创建的对象)。
你应该拥有的是一个共享锁,可能是使用一个静态变量,它在同一个类的所有实例之间共享,
或者将锁作为参数传递给笑脸的CTOR。
我将根据@Jonathon Reinhart使用重入锁的建议为第二个选项提供示例
public class Smiley extends Thread
{
private ReentantLock lock;
public Smiley(ReentrantLock lock) {
this.lock = lock;
}
@Override
public void run()
{
while(true)
{
try {
lock.lock();
System.out.print(":");
Thread.sleep(100);
System.out.print("-");
Thread.sleep(100);
System.out.println(")");
Thread.sleep(100);
}
catch(InterruptedException e) {
e.printStackTrace();
}
finally {
lock.unlock();
}
}
}
}
public static void main(String[] args)
{
ReentrantLock lock = new ReentantLock();
new Smiley(lock).start();
new Smiley(lock).start();
}
一些指示 -
一个。请记住,解锁代码必须在finally子句中 - 这是一个很好的做法(你也可以尝试阻止,最后阻塞,没有catch块)。
湾您可以考虑使用java.util.concurrent包中的其他锁替换ReentrantLock - 根据您的需要
答案 2 :(得分:1)
这实际上是你要问的两个问题,答案是:
因为您正在获取两个不同的隐式锁,所以允许同步块内的指令由两个线程同时执行,并且实际上可能是交错的。
您无需在静态级别进行同步。您需要在线程共享的对象的同一实例上进行同步。
实现所需内容的最简单方法是以下列方式在System.out上进行同步:
@Override
public void run() {
while (true) {
synchronized (System.out) {
try {
System.out.print(":");
Thread.sleep(100);
System.out.print("-");
Thread.sleep(100);
System.out.println(")");
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}