Synchronized的三种写法

文章目录

  • 前言
  • 一、synchronized是什么
  • 二、synchronized的三种写法
    • 1、同步代码块
    • 2、在实例方法上使用synchronized
    • 3、在静态方法上使用synchronized
  • 总结





前言

总结一下自己在学习Synchronized 以及它的三种写法。

一、synchronized是什么?

synchronized是由JVM实现的一种互斥同步的一种方式,被synchronized修饰过的程序块在编译前后被编译器生成了monitorenter和monitorexit两个字节码指令。

如果这个方法使用了synchronized的时候,代表它加上了锁,运行此方法的时都要检查它有没有被其他线程正在使用(或者该类的其他同步方法),有的话要等它使用完,没有的话则直接锁定调用者,然后直接运行。它包括两种用法:synchronized方法和synchronized块。



二、synchronized的三种写法




1、同步代码块

代码如下(示例):

package com.demo;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyClass mc=new MyClass();
        
        Thread t1=new MyThread(mc);
        Thread t2=new MyThread(mc);
        
        t1.setName("t1");
        t2.setName("t2");
        
        t1.start();
        Thread.sleep(1000);//这个睡眠的作用 是为了保证t1线程先执行。
        t2.start();
    }

}

class MyThread extends Thread {
    private MyClass mc;
    
    public MyThread (MyClass mc) {
        this.mc = mc;
    }
    
    public void run(){
        if(Thread.currentThread().getName().equals("t1")) {
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")) {
            mc.doOther();
        }
    }
    
}

class MyClass{
    //synchronized出现再类方法上,表示锁this。
    public synchronized void doSome(){
        System.out.println("doSome 执行开始");
        try {
            Thread .sleep(1000*5);//睡眠五秒
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("doSome 执行结束");
    }
    
    public void doOther() {
        System.out.println("doOther 执行开始");
        System.out.println("doOther 执行结束");
    }
}
doOther方法执行的时候不需要等待被修饰过的doSome方法结束,因为doOther方法没有被synchronized修饰,所以它不用排队等待。 

2、在实例方法上使用synchronized

代码如下(示例):

package com.demo;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyClass mc=new MyClass();
        
        Thread t1=new MyThread(mc);
        Thread t2=new MyThread(mc);
        
        t1.setName("t1");
        t2.setName("t2");
        
        t1.start();
        Thread.sleep(1000);//这个睡眠的作用 是为了保证t1线程先执行。
        t2.start();
    }

}

class MyThread extends Thread {
    private MyClass mc;
    
    public MyThread (MyClass mc) {
        this.mc = mc;
    }
    
    public void run(){
        if(Thread.currentThread().getName().equals("t1")) {
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")) {
            mc.doOther();
        }
    }
    
}

class MyClass{
    //synchronized出现再类方法上,表示锁this。
    public synchronized void doSome(){
        System.out.println("doSome 执行开始");
        try {
            Thread .sleep(1000*5);//睡眠五秒
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("doSome 执行结束");
    }
    
    public synchronized void doOther() {
        System.out.println("doOther 执行开始");
        System.out.println("doOther 执行结束");
    }
}
在两个方法前都加上synchronized修饰,doOther方法执行的时候需要等待doSome方法结束完之后才执行doSome,因为锁被doSome占了,所以要排队等待。 
我们再开启一个线程:package com.demo;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        //开启两个线程
        MyClass mc1=new MyClass();
        MyClass mc2=new MyClass();
        
        Thread t1=new MyThread(mc1);
        Thread t2=new MyThread(mc2);
        
        t1.setName("t1");
        t2.setName("t2");
        
        t1.start();
        Thread.sleep(1000);//这个睡眠的作用 是为了保证t1线程先执行。
        t2.start();
    }

}

class MyThread extends Thread {
    private MyClass mc;
    
    public MyThread (MyClass mc) {
        this.mc = mc;
    }
    
    public void run(){
        if(Thread.currentThread().getName().equals("t1")) {
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")) {
            mc.doOther();
        }
    }
    
}

class MyClass{
    //synchronized出现再类方法上,表示锁this。
    public synchronized void doSome(){
        System.out.println("doSome 执行开始");
        try {
            Thread .sleep(1000*5);//睡眠5秒
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("doSome 执行结束");
    }
    
    public synchronized void doOther() {
        System.out.println("doOther 执行开始");
        System.out.println("doOther 执行结束");
    }
}doOther方法执行的时候不需要等待doSome方法结束,因为MyClass对象是两个,两把锁,互不干涉。 

3、在静态方法上使用synchronized

package com.demo;


public class Demo {
    public static void main(String[] args) throws InterruptedException {
        //开启两个线程
        MyClass mc1=new MyClass();
        MyClass mc2=new MyClass();
        
        Thread t1=new MyThread(mc1);
        Thread t2=new MyThread(mc2);
        
        t1.setName("t1");
        t2.setName("t2");
        
        t1.start();
        Thread.sleep(1000);//这个睡眠的作用 是为了保证t1线程先执行。
        t2.start();
    }

}

class MyThread extends Thread {
    private MyClass mc;
    
    public MyThread (MyClass mc) {
        this.mc = mc;
    }
    
    public void run(){
        if(Thread.currentThread().getName().equals("t1")) {
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")) {
            mc.doOther();
        }
    }
    
}

class MyClass{
    //synchronized出现再类方法上,表示锁this。
    public synchronized static void doSome(){
        System.out.println("doSome 执行开始");
        try {
            Thread .sleep(1000*5);//睡眠5秒
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("doSome 执行结束");
    }
    
    public synchronized static void doOther() {
        System.out.println("doOther 执行开始");
        System.out.println("doOther 执行结束");
    }
}

doOther方法执行的时候不需要等待doSome方法结束,因为静态方法是类锁,不管创建了几个对象,类锁只有一把。





总结

对象锁:1个对象1把锁,100个对象有100把锁。

类锁:100个对象,全部都是这一把锁。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
单例模式一般有以下几种写法: 1. 懒汉式单例模式:在第一次使用时才创建实例,线程不安全,可以使用synchronized关键字进行同步,但是会影响性能。 ```java public class Singleton { private static Singleton instance = null; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 2. 饿汉式单例模式:在类加载时就创建实例,线程安全,但是无法进行延迟加载。 ```java public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 3. 双重校验锁单例模式:使用双重校验锁机制,既能保证线程安全,又能够进行延迟加载。 ```java public class Singleton { private static volatile Singleton instance = null; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 4. 静态内部类单例模式:使用静态内部类实现单例模式,既能保证线程安全,又能够进行延迟加载。 ```java public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } ``` 以上是几种常见的单例模式写法。需要注意的是,单例模式在多线程环境下需要特别小心,需要保证线程安全。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值