与synchronized有关的线程同步问题的一点非常规情况

2019-03-25 13:52|来源: 网路

package thread;

public class SyncTest implements Runnable {

/**
* 深入理解多线程。
* @param args
*/
private int x;
private int y;
public void run(){
synchronized(this){
x++;
y++;
}
System.out.println(Thread.currentThread().getName()+",x="+x+",y="+y);//注意此打印语句不在同步块中。
}
// 下面是几种输出结果
// Thread-1,x=2,y=2                  
// Thread-0,x=1,y=2

// Thread-1,x=2,y=2
// Thread-0,x=2,y=2

// Thread-1,x=2,y=2
// Thread-0,x=1,y=1




public static void main(String[] args) {
// TODO Auto-generated method stub
SyncTest that=new SyncTest();
new Thread(that).start();
new Thread(that).start();
     
}

}
不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;

如果上面的二句话正确的话,现在又有了不同的疑问:被synchronized修饰的代码块能在没执行完的情况下跳出??

问题补充:
shadabing 写道
1 上面两句话是正确的
2 被synchronized修饰的代码块需要执行完才能跳出
3synchronized修饰代码块,是保证资源同时不被多个线程访问

请您解释一下为什么会有第一种输出结果?以及this

问题补充:
shadabing 写道
{
   x++;
   y++;
}
这段代码是同步的

打印下面代码
Thread.currentThread().getName()+",x="+x+",y="+y
是同步的,可以看看jdk源代码,使用了synchronized关键字

但是x="+x+",y="+y连接语句就不一定是同步的,故输出结果也就不同了

嗯。谢谢

相关问答

更多
  • 如果您的程序是单线程的,则无需同步方法。 另一种情况是你编写一个库并指出它不是线程安全的。 然后,用户将负责处理可能的多线程使用,但您可以在没有同步的情况下编写所有内容。 If your program is single threaded, there's no need to synchronize methods. Another case would be that you write a library and indicate that it's not thread safe. The use ...
  • 看看你每次调用SyncMethod的构造函数时都在创建新的ABC实例,所以你有3个类的副本,每个副本都由不同的线程调用,所以他们不竞争监视器所以你需要的是使用相同的ABC对象这里所有3个电话都是解决方案 class SyncMethod implements Runnable { Thread t; ABC a; SyncMethod(String s, ABC a) { this.a = a; t = new Thread(this, s); t.start(); } pub ...
  • 是的,第二个线程可以在第一个线程开始 这可能是因为线程调度程序以不可预知的方式启动线程。 此外:首先可以先开始,但最后完成,因为线程之间的切换(由所提到的线程调度程序产生)。 即使你多次运行这个应用程序并'证明'订单将是相同的,但不能保证这个订单不会改变下一次运行。 Yes, second thread could start before first. This can be because thread scheduler starts threads in unpredictable manner. ...
  • 只要你只调用一次f这是安全的。 在变异数据的线程A和从线程A开始的线程B(HB-relationship在Thread.start )之间存在一个发生在之前的关系。 由于没有人在D启动后改变数据,这是安全的。 一些打破线程安全的方法: 再次变异,包括再次调用foo 从D以外的线程或调用foo的线程读取i 即使从调用foo的线程中你也不能再次变异的原因是这个突变会在d.start()之后发生,因此对于第二个突变没有HB边缘。 你无法从任意线程中读取i的原因是该线程没有明确定义的i++变异视图。 它可以比这更微 ...
  • 不要同步servlet的服务方法。 如果您同步servlet的service方法,实际上您正在为该Servlet实例一次为一个线程进行“访问保留”。 Struts ActionServlet类是一个HttpServlet ,基本上doGet和doPost方法在这里很有用。 如果我们要谈论Struts,那么流程方法是主要的切入点,但同样的原则适用于所有方法,就像它对一般service方法一样。 这个想法是这样的。 在web.app声明servlet时,servlet容器(例如Tomcat)将只创建该servl ...
  • Java的内部锁(与synchronized关键字一起使用)是可重入的。 输入r1所需的锁定与输入r1所需的锁定相同。 已经拥有锁的线程可以重新获取它。 你可以想到线程获得相同锁的次数有一个计数器。 在方法r1 ,调用线程已经两次获得相同的锁。 一旦“计数”回到零,锁只能用于其他线程; 也就是说,一旦获得锁的线程释放它的次数与获得它的次数完全相同。 编辑 :以下是五个线程的示例,每个线程在两个需要相同锁定的相互递归方法之间跳转。 通过运行此示例,您可以看到没有线程将进入methodOne直到它之前的线程完全 ...
  • 是的,它有点特别。 wait释放在synchronized block中获取的锁,并挂起它的thread (获取锁的线程),这意味着其他线程将被允许获取锁并修改状态。 现在notify或notifyAll会唤醒睡眠中的线程并重新获取lock Yes, it is somehow special. wait releases the lock acquired in the synchronized block and and suspends it's thread (the thread that acq ...
  • AspectJ本身不创建线程:编织“仅”通过注入一些额外的指令来修改代码,但它继续在相同的上下文中运行。 切入点定义中的synchronized关键字没有任何用处。 如果你想要实现的是将所有调用(或执行,这意味着更少的修改代码) @Synchronizes到在同一个锁上使用@Synchronizes注释的方法,你需要一个around建议: public aspect SynchronizingAspect { private static final Object lock = new Object ...
  • 如果两个线程针对同一个对象运行,那么这不应该发生。 因此,我建议您为每个线程创建一个新对象,或者至少有一些线程在不同的对象上运行。 如果你确实需要多个对象,那么你不应该使用synchronized(this) ,你应该创建一个static final Object来进行synchronize 。 请不要在this.getClass()上同步,因为它会中断。 If the two threads are running against the same object then this should not ...
  • 您的代码中存在一些缺陷,这些缺陷会使其有时无法正常工作: 您调用了thread_A.start() ,然后检查了thread_A.isAlive() 。 现在,如果在检查thread_A.isAlive()条件之前已经完成thread_A.isAlive() ,该怎么办? thread_B和thread_C永远不会启动。 您的申请失败。 假设thread_A未完成且thread_A.isAlive()条件,则在Java线程调度程序不总是保证thread_B之前启动thread_B 。 你的申请再次失败。 假 ...