java线程安全(synchronized )

参考 Rowland 的博客:  网址:https://www.cnblogs.com/rwland/articles/9163183.html

java synchronized:方法锁、对象锁、类锁

其中:非静态方法锁和对象锁,都是对象实例的锁,即对象锁。应用于对象实例,实例可很多。

           静态方法或类,都是类锁,只有一个类。应用于静态方法或类的class。类只有一个。

 

一、修饰方法或代码块。

 

package synchronizeTest;

public class TestSynchronized1 {
	
	  public void test1()   
	    {    
	         synchronized(this)   //this为对象实例 ,对对象实例的加锁
	         {    
	              int i = 5;    
	              while( i-- > 0)   
	              {    
	                   System.out.println(Thread.currentThread().getName() + " : " + i);    
	                   try   
	                   {    
	                        Thread.sleep(500);    
	                   }   
	                   catch (InterruptedException ie)   
	                   {    
	                   }    
	              }    
	         }    
	    }    
	      
	    public synchronized void test2()    //对象实例的加锁
	    {    
	         int i = 5;    
	         while( i-- > 0)   
	         {    
	              System.out.println(Thread.currentThread().getName() + " : " + i);    
	              try   
	              {    
	                   Thread.sleep(500);    
	              }   
	              catch (InterruptedException ie)   
	              {    
	              }    
	         }    
	    }    
	      
	    public static void main(String[] args)   
	    {    
	         final TestSynchronized1 myt2 = new TestSynchronized1();    
	         Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );    
	         Thread test2 = new Thread(  new Runnable() {  public void run() { myt2.test2();   }  }, "test2"  );    
	         test1.start();;    
	         test2.start();    
//	         TestRunnable tr=new TestRunnable();  
//	         Thread test3=new Thread(tr);  
//	         test3.start();  
	    }  

}

第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象。第二个方法是修饰方法的方式进行同步。所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。

 

输出为:

test1 : 4
test1 : 3
test1 : 2
test1 : 1
test1 : 0
test2 : 4
test2 : 3
test2 : 2
test2 : 1
test2 : 0
 

如果去掉test2方法的synchronized关键字,则会交替输出。不占用线程锁。

 

二、类锁的修饰(静态)方法和代码块:

package synchronizeTest;

public class TestSynchronized2 {

	public void test1()   
    {    
         synchronized(TestSynchronized2.class)   
         {    
              int i = 5;    
              while( i-- > 0)   
              {    
                   System.out.println(Thread.currentThread().getName() + " : " + i);    
                   try   
                   {    
                        Thread.sleep(500);    
                   }   
                   catch (InterruptedException ie)   
                   {    
                   }    
              }    
         }    
    }    
      
    public static synchronized void test2()   
    {    
         int i = 5;    
         while( i-- > 0)   
         {    
              System.out.println(Thread.currentThread().getName() + " : " + i);    
              try   
              {    
                   Thread.sleep(500);    
              }   
              catch (InterruptedException ie)   
              {    
              }    
         }    
    }    
      
    public static void main(String[] args)   
    {    
         final TestSynchronized2 myt2 = new TestSynchronized2();    
         Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );    
         Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized2.test2();   }  }, "test2"  );    
         test1.start();    
         test2.start();    
//         TestRunnable tr=new TestRunnable();  
//         Thread test3=new Thread(tr);  
//         test3.start();  
    }   
    
}

都是对类加锁,此时是一个锁。静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。

test1 : 4
test1 : 3
test1 : 2
test1 : 1
test1 : 0
test2 : 4
test2 : 3
test2 : 2
test2 : 1
test2 : 0
 

synchronized同时修饰静态和非静态方法,锁不同,则不会有线程并发问题。

 

 

1 类中方法内部的私有变量是线程安全的。类中直接变量是非线程安全的。

public class Hasprivate{

     public void addI(){

        int num=0; //方法内部私有变量 ,此时num是线程安全

     }

}

public class Hasprivate{

        private int num=0;  //类中直接是非线程安全

 public void addI(){

   

     }

}

 

public class Hasprivate{

  private int num=0;  //类中直接是非线程安全,但后面添加 synchronized 也是线程安全的

 synchronized public void addI(){

   

     }

}

 

2 synchronized关键字加到static静态方法上是给Class类上锁,而synchronized关键字加到非static静态方法上是给对象上锁。

public class Service{

    synchronized public void methodA(){

      System.out.println("methodA begin");

        while(true){

        }

    System.out.println("methodA    end");

    }

    synchronized public void methodB(){

      System.out.println("methodB begin");

     System.out.println("methodB   end");

    }

//如果有2个线程,都采用同一个实例化对象Service,则一个线程调用methodA方法,一个调用methodB方法,则输出为:

methodA begin.

剩下无法输出。

原因为:synchronized方法是对实例化对象Service加锁,当调用methodA方法时,由于一直在执行,无法执行完methodA方法,故该对象锁,一直未释放,故methodB无法执行。

为解决上面的问题,故:

 

public class Service{

Object object1=new Object();  

  public void methodA(){

synchronized  (object1){ 

    System.out.println("methodA begin");

        while(true){

        }

    System.out.println("methodA    end");

    }

}

Object object2=new Object();  

    public void methodB(){

synchronized (object2){

   System.out.println("methodB begin");

     System.out.println("methodB   end");

}   
    }

//此时可输出:方法内部锁,不对实例Service对象加锁

methodA begin

methodB begin

methodB end.

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值