Synchronized在不同位置的用法

介绍

Synchronized是java内置的一个关键字,是一种同步锁,可以用有几种用法:

  • 修饰一个代码块,被修饰的代码块称为同步代码块;
  • 修饰一个实例方法,被修饰方法称为同步方法,作用范围为整个方法本身,作用对象为调用这个方法的实例对象;
  • 修饰一个静态方法,其作用范围是整个静态方法,作用的对象为这个类(个人理解:因为静态方法是通过类名.的方式调用的,所以Synchronized锁的是整个类而不是对象);
  • 修饰一个类,其作用范围是synchronized后面括号的部分,作用的对象是这个类的所有对象。

修饰一个代码块

synchronized (this){//this,锁
    //同步代码块;
}

例子:创建一个对象时,使用synchronized时

package Synchronized;

public class Demo01 {
    public static void main(String[] args) {
        Syc syc = new Syc();
        Thread thread1 = new Thread(syc,"t1");
        Thread thread2 = new Thread(syc,"t2");
        thread1.start();
        thread2.start();
    }
}
class Syc implements Runnable{
    private static  int count;

    public Syc() {
        count = 0;
    }

    @Override
    public void run() {
        synchronized (this){
            for (int i =0; i< 5;i++){
                try {
                    System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static int getCount() {
        return count;
    }
}

image-20211127151844347

创建一个对象时,不使用Synchronized

package Synchronized;

public class Demo01 {
    public static void main(String[] args) {
        Syc syc = new Syc();
        Thread thread1 = new Thread(syc,"t1");
        Thread thread2 = new Thread(syc,"t2");
        thread1.start();
        thread2.start();
    }
}
class Syc implements Runnable{
    private static  int count;

    public Syc() {
        count = 0;
    }

    @Override
    public void run() {
            for (int i =0; i< 5;i++){
                try {
                    System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        
    }

    public static int getCount() {
        return count;
    }
}

image-20211127151926731

Thread2必须等到Thread1执行完毕之后,释放锁,才可以执行并获得这个锁

创建两个对象使用synchronized时

package Synchronized;

public class Demo01 {
    public static void main(String[] args) {
        Syc syc = new Syc();
        Syc syc1 = new Syc();
        Thread thread1 = new Thread(syc,"t1");
        Thread thread2 = new Thread(syc1,"t2");
        thread1.start();
        thread2.start();
    }
}
class Syc implements Runnable{
    private static  int count;

    public Syc() {
        count = 0;
    }

    @Override
    public void run() {
        synchronized (this){
            for (int i =0; i< 5;i++){
                try {
                    System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static int getCount() {
        return count;
    }
}

image-20211127152319856

因为创建了两个Syn的对象,两个线程执行的是两个对象的run方法lsynchronized锁定是的this这个对象,这时候因为创建了两个对象会有两把锁,分别锁定thread1和thread2,两把锁互不干扰,所以可以同时执行

当一个线程访问synchronized代码块是,另一个线程访问不带有synchronized时

package Synchronized;

public class Demo02 {
    public static void main(String[] args) {
        Syc2 syc = new Syc2();
        Thread thread1 = new Thread(syc,"t1");
        Thread thread2 = new Thread(syc,"t2");
        thread1.start();
        thread2.start();
    }
}
class Syc2 implements Runnable{
    private static  int count;

    public Syc2() {
        count = 0;
    }

    public void add(){
        synchronized (this){
            for (int i =0; i< 5;i++){
                try {
                    System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void print(){
        for (int i =0; i< 5;i++){
            try {
                System.out.println("线程" + Thread.currentThread().getName() + "," + count);
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run() {
       String thraedstr = Thread.currentThread().getName();
       if (thraedstr.equals("t1")){
           add();
       }else if (thraedstr.equals("t2")){
           print();
       }
    }

    public static int getCount() {
        return count;
    }
}

image-20211127153230323

thread1访问带有synchronized代码块时,thread2可以访问不带有synchronied的代码块,不会受到阻塞

修饰一个实例方法

public synchronized void method(){

}

注意:synchronized关键字修饰的方法不能被继承

虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字

class Parent {
   public synchronized void method() { }
}
class Child extends Parent {
   public synchronized void method() { }
}
class Parent {
   public synchronized void method() {   }
}
class Child extends Parent {
   public void method() { super.method();   }
}

定义接口时不能使用Synchronized

构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。

修饰一个静态方法

public synchronized static void method(){

}

使用synchronized时

package Synchronized;

public class Demo03 {
    public static void main(String[] args) {
        Syn3 syn3 = new Syn3();
        Thread thread1 = new Thread(syn3,"t1");
        Thread thread2 = new Thread(syn3,"t2");
        thread1.start();
        thread2.start();
    }
}
class Syn3 implements Runnable{
    private static int count;

    public Syn3() {
        count =0;
    }

    public static int getCount() {
        return count;
    }

    public synchronized static void add(){
        for (int i =0; i< 5; i++){
            try {
                System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run() {
        add();
    }
}

image-20211127154626814

Thread1和Thread2是Syn3的两个线程,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以Thread1和Thread2相当于用了同一把锁。这与使用关键字synchronized运行结果相同

修饰一个类

class ClassN {
    public void method() {
        synchronized(ClassN.class) {

        }
    }
}
package Synchronized;

import java.util.ArrayList;
import java.util.List;

public class Demo04 {
    public static void main(String[] args) {
        Sync sync = new Sync();
        Thread thread1 = new Thread(sync, "Thread1");
        Thread thread2 = new Thread(sync, "Thread2");
        thread1.start();
        thread2.start();
    }
}

class Sync implements Runnable {
    private static int count;

    public Sync() {
        count = 0;
    }

    public static void method() {
        synchronized(Sync.class) {
            for (int i = 0; i < 5; i ++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void run() {
        method();
    }
}

image-20211127155124408

和静态方法一样,synchronized作用于一个类的时候,是给这个类加了一把锁

总结:

  • 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
  • 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制

Synchronized放在不同的位置总结代码

package ThreadExam1;
/*
t2不需要等到t1执行,只有doSome有锁
*/

public class Test01 {
    public static void main(String[] args) {
        M m = new M();
        Thread t1 = new MyThread(m);
        Thread t2 = new MyThread(m);
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        try {
            Thread.sleep(1000);//保证t1线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();

    }

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

    }

}
class M {
    public synchronized void doSome(){//线程安全的方法
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }
    public void doOther(){//非线程安全的方法
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}
package ThreadExam2;
/*
t2需要等t1执行结束,doSome和doOther都是this这把锁
*/

public class Test01 {
    public static void main(String[] args) {
        M m = new M();
        Thread t1 = new MyThread(m);
        Thread t2 = new MyThread(m);
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        try {
            Thread.sleep(1000);//保证t1线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();

    }

}

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

    }

}

class M {
    public synchronized void doSome(){//锁 是 this
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }
    public synchronized void doOther(){//锁 是 this
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}
package ThreadExam3;
/*
两个线程对象,所以t2不需要等t1执行
*/
public class Test01 {
    public static void main(String[] args) {
        M m = new M();
        M m1 = new M();
        Thread t1 = new MyThread(m);
        Thread t2 = new MyThread(m1);
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        try {
            Thread.sleep(1000);//保证t1线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();

    }

}

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

    }

}

class M {
    public synchronized void doSome(){//锁 是 this
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }
    public synchronized void doOther(){//锁 是 this
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}
package ThreadExam4;
/*
静态方法是类锁,所以t2需要等t1执行
*/
public class Test01 {
    public static void main(String[] args) {
        M m = new M();
        M m1 = new M();
        Thread t1 = new MyThread(m);
        Thread t2 = new MyThread(m1);
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        try {
            Thread.sleep(1000);//保证t1线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();

    }

}

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

    }

}

class M {
    public synchronized static void doSome(){//锁 是 this
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }
    public synchronized static void doOther(){//锁 是 this
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}
    m.doSome();
        }
        if(Thread.currentThread().getName() == "t2"){
            m.doOther();
        }

    }

}

class M {
    public synchronized static void doSome(){//锁 是 this
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }
    public synchronized static void doOther(){//锁 是 this
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小七rrrrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值