synchronized同步语句块(一)

用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待较长时间。可以使用synchronized同步语句块。

public class NoSysnTest {
    public  void play(){
         try{
             //其他无关紧要的部分,放到代码块外部,节省时间
             System.out.println("sleep begin threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             Thread.sleep(5000);
              System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());

                synchronized (this){
                    //涉及到主要的操作的,避免 非线程安全的 部分可以放到代码块中
                }
             System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());

         }catch (InterruptedException e){

          }
    }
}

当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized同步代码块。

二、一半异步,一半同步
不在synchronized块中就是异步执行,在synchronized块中就是同步执行。

public class NoSysnTest {
    public  void play(){
            //异步执行
             for(int i=0;i<100;i++){
                 System.out.println("异步 threadName"+Thread.currentThread().getName()+" i="+i);
             }
             synchronized (this){
                    //同步执行
                 for(int i=0;i<100;i++){
                     System.out.println("同步 threadName"+Thread.currentThread().getName()+" i="+i);
                 }
                }
             System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
    }
}

结果:
异步 threadNameB i=20
异步 threadNameB i=21
异步 threadNameA i=0
异步 threadNameA i=1
。。。
异步 threadNameB i=98
异步 threadNameB i=99
同步 threadNameB i=0
同步 threadNameB i=1
同步 threadNameB i=2
同步 threadNameB i=3
。。。

三、synchronized代码块间的同步性
一个线程访问object的一个synchronized同步代码块时,其他线程同一个object中所有其他的synchronized同步代码块(可以是不同的方法中的)的访问将被阻塞

public class NoSysnTest {
    public  void play(){
        //线程A调用该代码块,其他的线程也不能调用service()方法中的代码块
             synchronized (this){
                 System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             }
      }

    public void service(){
        //只有等到线程A调用完毕,线程B才能调用该代码块
        synchronized (this){
            System.out.println("threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());

        }
    }
}

多线程调用同一个对象中的不同名称的synchronized**同步方法或synchronized(this)同步代码块时,调用的效果是按顺序执行,也就是同步的**,阻塞的。

四、将任意对象作为对象监视器
这个“任意对象”大多数是实例变量方法的参数,使用格式是synchronized(非this对象)
它的规则是:
4.1、在多个线程持有“对象监视器”为同一个对象(相同的实例变量 或者 方法参数 )的前提下,同一时间只有一个线程可以执行synchronized(非this对象)同步代码块中的代码。

public class NoSysnTest {
    private String anyStr=new String();
    public  void play(){
            //使用 实例变量作为 对象监视器
             synchronized (anyStr){
                 System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             }
      }
}
//针对一个NoSysnTest 实例对象,它的**实例变量anyStr**对于线程A 和线程B来说都是一样的,因此只有一个线程可以调用该代码块。
//但是如果**把 anyStr 对象实例 放在方法里**。那就是不同的对象,那就是异步了(不是同一个锁)。

4.2、当持有”对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象)同步代码块中的代码

锁非this对象的优点:
如果在一个类中有很多个synchronized方法,虽然能实现同步,但是会受到阻塞,所以影响运行效率;如果使用同步代码块非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,可以提高效率。

//由于对象监视器不同,所以运行结果是异步的
public class NoSysnTest {
    private String anyStr=new String();
    public  void play(){
            //使用 实例变量作为 对象监视器
             synchronized (anyStr){
                 System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             }
      }
      //同步方法
    synchronized public void service(){
        System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());

    }
}

三个结论:
1、当多个线程同时执行synchronized(非this对象 x)同步代码块时呈同步效果(监视器对象是一样的)。

public class NoSysnTest {
    public  void play(CountOperate operate){
            //使用 实例变量作为 对象监视器
             synchronized (operate){
                 System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             }
      }
}

2、当其他线程执行x对象(也就是监控器对象)中synchronized同步方法时呈同步效果。

//监控器对象
public class HasSelfPrivateNum {
//线程B调用了该同步方法
     public synchronized void addI(String userName,NoSysnTest noSysnTest){
         System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
     }
}


public class NoSysnTest {
//线程A调用了该代码块
    public  void play(HasSelfPrivateNum priNum){
            //使用 实例变量作为 对象监视器
             synchronized (priNum){
                 System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
             }
      }
}

结果:线程A 和 线程B 是同步的

3、当其他线程执行x对象(也就是监控器对象)中synchronized(this)代码块时也呈同步效果。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值