线程同步与synchronized

看如下代码:

package project;
public class Demo {
	public static void main(String []args){
		final Out out=new Out();
		new Thread(){
			public void run(){
				int i=0;
				while(i<5){
					i++;
				out.print("1111111111");
				}
			}
		}.start();
		new Thread(){
			public void run(){
				int i=0;
				while(i<5){
					i++;
				out.print("2222222222");
				}
			}
		}.start();
	}
	

}
class Out{
	public void print(String str){
		for(int i=0;i<str.length();i++){
			System.out.print(str.charAt(i));
		}
		System.out.println();
	}
}

运行结果:

 理想的打印应该是每行只有12并且每行10个数字,而上面却出现了行内数字个数不为10,1中还夹杂着2。

那么出现这种现象的原因是什么呢?

线程并不是同时执行的,而是CPU快速的在这线程之间切换执行,由于切换速度极快使我们感觉同时执行罢了。

在这里,A线程在还没有执行完print()方法时,就切换到了B线程调用了print(),然后在B线程结束或者还没结束又切换到了A线程,如此反复,造成的结果。

那么怎么控制在A(或B)线程在调用print()方法时,另一个线程不调用print()方法呢?

针对线程同步问题java早就有解决方法了,最简单的就是给方法加上synchronized关键字,如下:

class Out{
	public synchronized void  print(String str){
		for(int i=0;i<str.length();i++){
			System.out.print(str.charAt(i));
		}
		System.out.println();
	}
}

这样结果就会是理想状态的结果了:

这是什么意思呢?加上synchronized关键字后,比如A线程执行print()方法就相当于拿到了一把,只有获取这个锁才能执行此方法,如果在A线程执行print()方法过程中B线程也想插一脚进来执行print()方法,对不起此时这是不能够的,因为此时锁在A线程手里,B线程无权拿到这把锁,只有等到A线程执行完后放弃锁,B线程才能拿到锁执行print()方法。

为print()方法加上synchronized后其就变成了同步方法,普通同步方法的锁是this,也就是当前对象,比如Demo中,外部要想调用print()方法就必须创建Out类实例对象out,此时print()同步方法的锁就是这个out。

我们还可以通过同步代码块

写法:synchronized(obj){},其中obj为锁对象。

如这里,修改Out类:

class Out{
	public void  print(String str){
		synchronized(this){
		for(int i=0;i<str.length();i++){
			System.out.print(str.charAt(i));
		}
		System.out.println();
		}
	}
}

这样结果还会是理想状态:

原因是在执行同步代码块里面的内容的线程 获得了锁,只有在它执行完毕后释放了锁,其他线程才能获得锁,并执行代码块里面的内容。

如上是对一个类的一个对象,里面的方法或者代码块加锁。

如果是一个类的多个对象呢?会出现什么情况?看下面一段代码:

package project;
public class Demo {
	public static void main(String []args){
		final Out out1=new Out();
		final Out out2=new Out();
		new Thread(){
			public void run(){
				int i=0;
				while(i<5){
					i++;
				out1.print("1111111111");
				}
			}
		}.start();
		new Thread(){
			public void run(){
				int i=0;
				while(i<5){
					i++;
				out2.print("2222222222");
				}
			}
		}.start();
	}
	

}
class Out{
	public void  print(String str){
		synchronized(this){
		for(int i=0;i<str.length();i++){
			System.out.print(str.charAt(i));
		}
		System.out.println();
		}
	}
}

上面的代码了,创建了两个Out类对象,两个线程分别执行不同的对象的print()方法 。

看下运行结果:

很显然,结果并不理想,synchronized 加锁并没起作用。

原因:synchronized 的锁对象为this,也就是当前实例对象,但这里是同一个类的不同对象实例,两个线程访问的不是同一个对象,所以synchronized并不会起作用。

那么这里要怎么让synchronized起作用呢?

让synchronized锁这个类对应的Class对象。

修改Out类:

class Out{
	public void  print(String str){
		synchronized(Out.class){
		for(int i=0;i<str.length();i++){
			System.out.print(str.charAt(i));
		}
		System.out.println();
		}
	}
}

以上将synchronized(this)改为了synchronized(Out.class)

运行结果如下:

这样加锁后,就算不是同一个类的实例对象,锁也能起作用。 

猜你喜欢

转载自blog.csdn.net/cc1969281777/article/details/82844829