美文网首页
二(Synchronized)多线程访问同步方法的七种具体情况

二(Synchronized)多线程访问同步方法的七种具体情况

作者: 讲道理很没道理 | 来源:发表于2019-02-26 11:35 被阅读0次

1.两个线程同时访问一个对象的同步方法

/**
 * @author sxylml
 * @Date : 2019/2/26 09:29
 * @Description:
 * 两个线程同时访问一个对象的同步方法
 */
public class SynchronizedObjectMethod implements Runnable {


    @Override
    public void run() {
        method();

    }

    /**
     * 默认以this 对象作为锁。
     */
    public synchronized void method() {

        System.out.println("对象锁的方法修饰符形式,我叫:" + Thread.currentThread().getName());

        try {
            System.out.println(Thread.currentThread().getName() + " 休眠3秒");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "运行结束");

    }


    public static void main(String[] args) {
        Long startTime = System.currentTimeMillis();
        Runnable instance = new SynchronizedObjectMethod();

//        同一个实例的两个不同线程,访问同一个被synchronized 修饰的方法
//        争抢的是同一把锁 ,所以需要等待
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);

        t1.start();
        t2.start();

        while (t1.isAlive() || t2.isAlive()) {

        }

        Long endTime = System.currentTimeMillis();
        System.out.println("整个程序运行结束! 用时" + (endTime - startTime));

    }
}

需要争抢同一把锁this 所以顺序执行


image.png

2.两个线程访问的是两个对象的同步方法


/**
 * @author sxylml
 * @Date : 2019/2/26 10:58
 * @Description: 两个线程访问的是两个对象的同步方法
 */
public class SynchronizedTwoThreadToTwoObject implements Runnable {

    static Runnable instance1 = new SynchronizedTwoThreadToTwoObject();
    static Runnable instance2 = new SynchronizedTwoThreadToTwoObject();


    @Override
    public void run() {
//         当前对象作为锁

        synchronized (this) {


            String threadName = Thread.currentThread().getName();
            System.out.println("我是对象锁的代码块形式。我叫" + threadName);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是对象锁的代码块形式。我叫" + threadName + "运行结束!");

        }
    }

    public static void main(String[] args) {

        Long startTime = System.currentTimeMillis();

//        两个线程访问的是两个对象的同步方法,同时开始,同时结束,可以理解并行执行的
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        while (t1.isAlive() || t2.isAlive()) {

        }

        Long endTime = System.currentTimeMillis();
        System.out.println("整个程序运行结束! 用时" + (endTime - startTime));

    }

}

image.png

并行处理,不受干扰,锁的对象不是同一个
3.两个线程访问的是Synchronized的静态方法


/**
 * @author sxylml
 * @Date : 2019/2/26 10:04
 * @Description: 类锁的一种形式,static 形式
 * 
 * 两个线程访问的是Synchronized的静态方法
 */
public class SynchronizedClassStatic implements Runnable {

    static Runnable instatnce1 = new SynchronizedClassStatic();
    static Runnable instatnce2 = new SynchronizedClassStatic();

    public static synchronized void method() {

        System.out.println("我是类锁的第一种形式:static 形式,我叫:" + Thread.currentThread().getName());

        try {
            System.out.println(Thread.currentThread().getName() + "休眠3秒");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+" 运行结束");
    }


    @Override
    public void run() {
        method();
    }

    public static void main(String[] args) {

        Long startTime = System.currentTimeMillis();
//        instatnce1,instatnce2 不同的2个实例,如果不加 static 就可以同时运行。
        Thread t1 = new Thread(instatnce1);
        Thread t2 = new Thread(instatnce2);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        Long endTime = System.currentTimeMillis();

        System.out.println("finished 耗时"+(endTime-startTime));
    }
}

image.png

对应的锁是同一把,一个一个的顺序执行。

4.同时访问同步方法与非同步方法


/**
 * @author sxylml
 * @Date : 2019/2/26 11:09
 * @Description: 同时访问同步方法与非同步方法
 */
public class SynchronizedYesOrNo implements Runnable {

    static Runnable instance1 = new SynchronizedYesOrNo();
    @Override
    public void run() {

        if ("Thread-0".equals(Thread.currentThread().getName())) {
            method1();
        } else {
            method2();
        }


    }
    public synchronized void method1(){

        System.out.println("我是synchronized 修饰的加锁的方法:我叫" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +"  运行结束");

    }
    public  void method2(){

        System.out.println("我是没加锁方法:我叫" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +"  运行结束");

    }


    public static void main(String[] args) {

        Long startTime = System.currentTimeMillis();

//        两个线程访问的是两个对象的同步方法,同时开始,同时结束,可以理解并行执行的
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance1);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        while (t1.isAlive() || t2.isAlive()) {

        }

        Long endTime = System.currentTimeMillis();
        System.out.println("整个程序运行结束! 用时" + (endTime - startTime));

    }


}
image.png

非同步方法不受影响。

5.访问同一个对象的不同的普通同步方法


/**
 * @author sxylml
 * @Date : 2019/2/26 11:19
 * @Description: 访问同一个对象的不同的普通同步方法
 */
public class SynchronizedDifferentMethod implements Runnable {

    static Runnable instance = new SynchronizedDifferentMethod();

    @Override
    public void run() {

        if ("Thread-0".equals(Thread.currentThread().getName())) {
            method1();
        } else {
            method2();
        }

    }

    public synchronized void method1() {

        System.out.println("我是synchronized 修饰的加锁的方法1 :当前调用线程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "  运行结束");

    }

    public synchronized void method2() {

        System.out.println("我是synchronized 修饰的加锁的方法2 :当前调用线程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "  运行结束");

    }


    public static void main(String[] args) {

        Long startTime = System.currentTimeMillis();

//        两个线程访问的是两个对象的同步方法,同时开始,同时结束,可以理解并行执行的
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        while (t1.isAlive() || t2.isAlive()) {

        }
        Long endTime = System.currentTimeMillis();
        System.out.println("整个程序运行结束! 用时" + (endTime - startTime));

    }

}

image.png

拿到的是this 锁,所以呢,还是会受影响,串行执行。

6.同时访问静态synchronized和 非静态synchronized


/**
 * @author sxylml
 * @Date : 2019/2/26 11:19
 * @Description: 同时访问静态synchronized和 非静态synchronized
 *  由于锁的对象不一样,所以同时执行
 */
public class SynchronizedStaticAndNormal implements Runnable {

    static Runnable instance = new SynchronizedStaticAndNormal();

    @Override
    public void run() {

        if ("Thread-0".equals(Thread.currentThread().getName())) {
            method1();
        } else {
            method2();
        }

    }

    public synchronized static void method1() {

        System.out.println("我是synchronized 修饰静态static 的加锁的方法1 :当前调用线程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "  运行结束");

    }

    public synchronized void method2() {

        System.out.println("我是synchronized 修饰的加锁的方法2 :当前调用线程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "  运行结束");

    }


    public static void main(String[] args) {

        Long startTime = System.currentTimeMillis();

//        两个线程访问的是两个对象的同步方法,同时开始,同时结束,可以理解并行执行的
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        while (t1.isAlive() || t2.isAlive()) {

        }
        Long endTime = System.currentTimeMillis();
        System.out.println("整个程序运行结束! 用时" + (endTime - startTime));

    }

}

image.png

7.方法抛出异常后,会释放锁。

总结:
1.一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应1,5题)
2.每一个实例都对应有自己的一把锁,不同实例之间互不影响,列外:
.锁对象是 *.class 以及synchronized 修饰的是static 方法的时候,所有对象公用一把类锁(对应,2,3,4,6)
3无论方法正常执行完毕或者方法抛出异常,都会释放锁。

4.目前进入被synchronized 的方法,在这方法里面调用没有synchronized 修饰的方法。还是线程安全的吗?

不是线程安全的,出了synchronized 就可以同时被多个线程调用。

相关文章

网友评论

      本文标题:二(Synchronized)多线程访问同步方法的七种具体情况

      本文链接:https://www.haomeiwen.com/subject/nnnoyqtx.html