Java并发编程:线程安全

 Java并发编程:线程安全 

当多个线程需要同时访问同一个资源(成为临界资源)时,可能会对数据造成破坏。 

例如:money += 1000;  当第一个线程取出money值,然后+1000完成这两步之后,第二个进程进入读取了count的值,又+1000 再赋值给count。 这时 第一个线程再进行第三步,把它的值赋给count,这就出现了混乱,没有达到预期的效果(两个线程只存进去了1000)。

所以,需要同步互斥访问来解决线程安全问题。 Java提供了  synchronized 和 Lock 方式进行同步互斥访问。

1.synchronized 关键字

->实例方法同步,对对象加锁

public synchronized void add(int i){
i += 1;
}

一个线程只能访问一个实例变量的add()方法

->静态方法同步

public static synchronized void add(int i){
i += 1;
}

同步在该方法所在的类对象(JVM中一个类只有一个类对象.class)上,所以同时只允许一个线程执行同一个类中的静态同步方法。

->实例方法中的同步块

public void add(int i){
synchronized(this){   //this指代调用add()方法的实例对象(即监视器对象),一次只有一个线程可以执行该同步代码块
   	i += 1;	 //当在某个线程中执行这段代码块,该线程获取这个对象的锁,从而使得其他线程无法同时访问该代码块。
   }
}

->静态方法中的同步块

	public static synchronized void add(int i){		//只能被类对象的一个线程访问
				synchronized(this){   
			    	i += 1;
			    }
			}

对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。

下面有两个栗子:

1).多个线程访问共享数据:设计4个线程,其中两个对j增加1,另外两个对j减少1

public class MultiThreadShareData {
		
			private int j;
			public static void main(String[] args) {
				MultiThreadShareData mts = new MultiThreadShareData();
				Inc inc = mts.new Inc(); 
				Dec dec = mts.new Dec();
				
				for(int i=0; i<2; i++){
					Thread t1 = new Thread(inc);
					t1.start();
					
					t1 = new Thread(dec);
					t1.start();
				}
			}
			
			private synchronized void inc(){
				j++;
				System.out.println(Thread.currentThread().getName() + "-inc:" + j);
			}
			
			private synchronized void dec(){
				j--;
				System.out.println(Thread.currentThread().getName() + "-dec:" + j);
			}
		
			class Inc implements Runnable{
				public void run() {
					for(int i=0; i<100; i++){
						inc();
					}
				}
			}
		
			class Dec implements Runnable {
				public void run() {
					for(int i=0; i<100; i++) {
						dec();
					}
				}
			}
}

 

2).设计程序:子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次。

public class ThreadCommunication {	
				public static void main(String[] args) {
					
					final Business bussiness = new Business();
					new Thread(new Runnable(){
						public void run() {
							for(int i=1; i<=50; i++){
								bussiness.sub(i);
							}
						}
					}).start();
					
					for(int i=1; i<=50; i++){
							bussiness.main(i);
					}
				}
			}
			
			class Business{
			private boolean bShouldSub = true;
			public synchronized void sub(int i) {
				while(!bShouldSub){
					try {
						this.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
					
				for(int j=1; j<=10; j++) {
						System.out.println("sub thread sequence of " + j + ", loop of " + i ); 
				}
				bShouldSub = false;
				this.notify();
				
			}
			
			public synchronized void main(int i) {
				while(bShouldSub){
					try {
						this.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}	
				}
				for(int j=1; j<=100; j++) {
					System.out.println("main thread sequence of " + j + ", loop of " + i ); 
				}
				bShouldSub = true;
				this.notify();
			}
		}

 

猜你喜欢

转载自lucas0802.iteye.com/blog/2213709