java多线程之共享资源(2)

转载请注明出处

http://blog.csdn.net/pony_maggie/article/details/42621771


作者:小马


接着上一篇,引入多线程中的同步机制。如果想让t1和t2只能被同一个线程执行,可以引入synchronized关键字。


只要在run方法前面加上这个关键字,就能保证这个方法当前一次只能被一个线程执行。可以这样理解: 一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A。
public synchronized void run()
		{
			while(true)
			{
				t1.setText(Integer.toString(count1++));
				t2.setText(Integer.toString(count2++));
				try 
				{
					sleep(500);
				} 
				catch (InterruptedException e) 
				{
					System.err.println("Interrupted");
				}
			}
		}



但是对于前一篇讲的示例,仅仅把run置为synchronized是不够的,因为这只能保证,一次只有一个线程调用run方法,还有一个监控方法synchTest,这个才是Watcher线程调用的,这是判断count1和count2是否相等的关键。


这就要用到synchronized另一个特性了, 当一个类中有多个synchronized方法时,可以确保同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突。所以新的synchTest函数如下:
public synchronized void synchTest()
		{
			Sharing2.incrementAccess();//追踪访问次数
			if(count1 != count2)
			{
				label.setText("Unsynched");
			}
		}


运行代码,似乎达到了我们要的效果,但是为什么access count不变化了呢? 难道synchTest根本没有执行?没错, 因为run函数是个无限循环,所以函数本身永远不会执行完(注意与sleep无关),根据上面讲的理论,其它线程根本没机会执行。


事实上,我们只是想让t1和t2同时执行而已,并不打算锁住整个run函数,好在java里还有一个synchronized块的概念,可以把想要锁住的代码块加到synchronized(current object)里,如下所示:
public void run()
		{
			while(true)
			{
				synchronized(this)
				{
					t1.setText(Integer.toString(count1++));
					t2.setText(Integer.toString(count2++));
				}
				
				try 
				{
					sleep(500);
				} 
				catch (InterruptedException e) 
				{
					System.err.println("Interrupted");
				}
			}
		}


最后需要注意的是,synchronized的开销非常大,在程序设计时,如果不是必要,尽量不要用。


你可能感兴趣的:(java,多线程,同步,synchronized)