synchronized知识点小结

Java的多线程编程中常用的关键字是synchronized,当然也经常用到java.util.concurrent.locks包下的一些类,比如ReentrantLock,还有java.util.concurrent.atomic包下的以Atomic开头的类。这个后续有机会再来探讨。
synchronized关键字,它可以用于声明方法,也可以用于声明代码块,以下是具体场景。
synchronized关键字修饰方法

package thread;

public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SynchronizedDemo{

    public synchronized void foo1() throws InterruptedException{
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"进入方法foo1");
        Thread.sleep(3000);
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"离开方法foo1");;
    }
}

运行结果:

线程A1477807162663进入方法foo1
线程A1477807165665离开方法foo1
线程B在1477807165665进入方法foo1
线程B在1477807168665离开方法foo1

synchronized关键字修饰代码块
synchronized关键字作用在代码块效果和作用在方法上类似,区别是作用在代码块上的参数是自己设置的,可以根据自己的需求设置锁定的对象,当一个类中有很多个synchronized方法时,使用同步代码块锁定非this对象,则可以避免和其他的同步方法争抢this锁,提高运行效率。 synchronized(非this对象x)格式是将x对象本身作为“对象监视器”,所以当多个线程同时执行synchronized(x){}同步代码块和synchronized同步方法呈同步效果;当其他线程执行x对象方法里面的synchronized关键字的方法时,也呈同步效果。

public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo("123");
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SynchronizedDemo{

    private String obj;

    public SynchronizedDemo(String str){

        this.obj = str;
    }
    public void foo2() throws InterruptedException{
        synchronized (obj){
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo2");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo2");;
        }
    }

}

运行结果:

线程A1477807251436进入方法foo2
线程A1477807254437离开方法foo2
线程B在1477807254437进入方法foo2
线程B在1477807257438离开方法foo2

synchronized锁重入
关键字Synchronized拥有锁重入的功能,也就是使用synchronized时,当一个线程得到一个对象锁后,再次请求对象锁时是可以再次获得对象的锁的,这也证明看在一个synchronized方法/代码块内部调用同一个对象的其他synchronized方法/代码块时,是永远可以得到锁的。

public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo("123");
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SynchronizedDemo{

    private String obj;

    public SynchronizedDemo(String str){

        this.obj = str;
    }

    public synchronized void foo1() throws InterruptedException{
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"进入方法foo1");
        foo2();
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"离开方法foo1");
    }

    public void foo2() throws InterruptedException{
        synchronized (obj){
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo2");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo2");;
        }
    }   
}

运行结果:

线程A1477807446886进入方法foo1
线程A1477807446886进入方法foo2
线程A1477807449887离开方法foo2
线程A1477807449887离开方法foo1
线程B在1477807449887进入方法foo1
线程B在1477807449887进入方法foo2
线程B在1477807452887离开方法foo2
线程B在1477807452887离开方法foo1

出现异常,锁自动释放
当一个线程执行的代码出现异常时,其所持有的锁会自动释放,这个较好理解,线程出现异常后,线程会停止,其拥有的锁自然会释放,我们在实际开发过程中要停止线程,一般不用stop方法,而是用其他方式,常用的方式有中断线程,捕获异常来停止线程。

public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo("123");
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
        threadA.interrupt();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
            demo.foo1();
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
            demo.foo1();
    }
}

class SynchronizedDemo{

    private String obj;

    public SynchronizedDemo(String str){

        this.obj = str;
    }

    public synchronized void foo1() {
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"进入方法foo1");
        try{
            foo2();
        }catch(InterruptedException e){
            System.out.println("线程"+Thread.currentThread().getName()+"中断了");
        }
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"离开方法foo1");
    }

    public void foo2() throws InterruptedException{
        synchronized (obj){
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo2");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo2");;
        }
    }

}

运行结果:

线程A1477807745022进入方法foo1
线程A1477807745022进入方法foo2
线程A中断了
线程A1477807745023离开方法foo1
线程B在1477807745023进入方法foo1
线程B在1477807745023进入方法foo2
线程B在1477807748024离开方法foo2
线程B在1477807748024离开方法foo1

同步不具有继承性
同步不可以继承,因此我们重写父类的synchronized方法时也要加上synchronized关键字,子类的方法才能实现同步。

静态同步synchronized方法与synchronized(class)代码块
关键字synchronized应用在static静态方法上,则是对Class类进行加锁,它与Class对应的对象锁不是同一个锁,Class锁可以对类的所有对象实例起作用,即同一个类的两个不同对象也是互斥的。

public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            SynchronizedDemo.foo2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SynchronizedDemo{

    public synchronized void foo1() throws InterruptedException {
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"进入方法foo1");
        Thread.sleep(3000);
        System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                +"离开方法foo1");
    }

    public static synchronized void foo2() throws InterruptedException{
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo2");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo2");;
    }

}

运行结果:

线程A1477808224594进入方法foo1
线程B在1477808224594进入方法foo2
线程B在1477808227595离开方法foo2
线程A1477808227595离开方法foo1
public class SynchronizedTest {

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();
        SynchronizedDemo demo1 = new SynchronizedDemo();
        Thread threadA = new ThreadA(demo);
        Thread threadB = new ThreadB(demo1);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{

    private SynchronizedDemo demo;
    public ThreadA(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadB extends Thread{

    private SynchronizedDemo demo;
    public ThreadB(SynchronizedDemo demo){
        this.demo = demo;
    }

    @Override
    public void run() {
        try {
            demo.foo2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SynchronizedDemo{

    public void foo1() throws InterruptedException {
        synchronized(SynchronizedDemo.class){
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo1");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo1");
        }
    }

    public  void foo2() throws InterruptedException{
        synchronized(SynchronizedDemo.class){
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"进入方法foo2");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+ System.currentTimeMillis()
                    +"离开方法foo2");;
        }
    }

}

运行结果:

线程A1477808373225进入方法foo2
线程A1477808376226离开方法foo2
线程B在1477808376226进入方法foo2
线程B在1477808379227离开方法foo2
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值