ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

多线程与并发 - 多线程访问同步方法的7种情况

2021-09-14 23:59:28  阅读:152  来源: 互联网

标签:同步 Thread getName System 并发 println 多线程 public out


不啰嗦,我们直接开始!

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

代码:

public class SynchronizedObjectMethod implements Runnable {
    static SynchronizedObjectMethod instance = new SynchronizedObjectMethod();

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

    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) {
        //两个线程访问一个对象的同步方法,对象为instance实例
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("fininshed");
    }
}

运行结果:

对象锁的方法修饰符形式,我叫:Thread-0
Thread-0 休眠3秒
Thread-0运行结束
对象锁的方法修饰符形式,我叫:Thread-1
Thread-1 休眠3秒
Thread-1运行结束
fininshed

解析:需要争抢同一把锁this,所以顺序执行。

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

代码:

public class SynchronizedTwoThreadToTwoObject implements Runnable {
    static SynchronizedTwoThreadToTwoObject instance1 = new SynchronizedTwoThreadToTwoObject();
    static SynchronizedTwoThreadToTwoObject instance2 = new SynchronizedTwoThreadToTwoObject();

    @Override
    public void run() {
        // 当前对象作为锁
        synchronized (this) {
            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) {
        //两个线程访问的是两个对象的同步方法,两个对象一个为instance1,另一个为instance2
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("fininshed");
    }
}

运行结果:

我是对象锁的代码块形式,我叫Thread-0
我是对象锁的代码块形式,我叫Thread-1
Thread-1运行结束
Thread-0运行结束
fininshed

解析:并行处理,不受干扰,锁的实例不是同一个。

3、两个线程访问的是Synchronized的静态方法

代码:

public class SynchronizedClassStatic implements Runnable {
    static SynchronizedClassStatic instance1=new SynchronizedClassStatic();
    static SynchronizedClassStatic instance2=new SynchronizedClassStatic();

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

    public static synchronized void method(){
        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){
        //两个线程访问synchronized的静态方法
        Thread t1=new Thread(instance1);
        Thread t2=new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive()){
        }
        System.out.println("fininshed");
    }
}

运行结果:

我是类锁的一种形式,我叫Thread-0
Thread-0线程结束
我是类锁的一种形式,我叫Thread-1
Thread-1线程结束
fininshed

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

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

代码:

public class SynchronizedYesOrNo implements Runnable {
    static SynchronizedYesOrNo instance=new SynchronizedYesOrNo();
    public static void main(String[] args) {
        Thread th1=new Thread(instance);
        Thread th2=new Thread(instance);
        th1.start();
        th2.start();
        while(th1.isAlive()||th2.isAlive()){

        }
        System.out.println("finished");
    }

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            method1();
        }else{
            method2();
        }
    }

    public synchronized void method1(){
        System.out.println("我是加了同步的方法"+Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束");
    }

    public synchronized static void method2(){
        System.out.println("我是没加了同步的方法"+Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束");

    }
}

运行结果:

我是加了同步的方法Thread-0
我是没加了同步的方法Thread-1
Thread-0结束
Thread-1结束
finished

解析:同步方法不会出现并发问题,非同步方法不会受到影响,出现并发问题。

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

代码:

public class SynchronizedDifferentMethod implements Runnable {
    static SynchronizedDifferentMethod instance=new SynchronizedDifferentMethod();

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            method1();
        }else {
            method2();
        }
    }

    public synchronized  void method1(){
        System.out.println("我是加锁的方法"+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("我也是加锁的方法"+Thread.currentThread().getName()+"线程执行结束");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"线程执行结束");
    }

    public static void main(String[] args) throws InterruptedException{
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive()){}
        System.out.println("fininshed");
    }
}

运行结果:

我是加锁的方法Thread-0
Thread-0线程执行结束
我也是加锁的方法Thread-1线程执行结束
Thread-1线程执行结束
fininshed

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

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

代码:

public class SynchronizedStaticAndNormal implements Runnable {
    static SynchronizedStaticAndNormal instance=new SynchronizedStaticAndNormal();

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            method1();
        }else {
            method2();
        }

    }

    public synchronized static void method1(){
        System.out.println("我是加锁的静态方法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("我是加锁的非静态方法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) throws InterruptedException{
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive()){}
        System.out.println("fininshed");
    }
}

运行结果:

我是加锁的静态方法1 Thread-0
我是加锁的非静态方法2 Thread-1
Thread-1线程执行结束
Thread-0线程执行结束
fininshed

解析:method1锁的是.class对象,method2锁的是this对象,锁不一样,没有冲突,并行执行。

7、方法抛异常后,会释放锁

代码:

public class SynchronizedException implements Runnable {
    static SynchronizedException instance = new SynchronizedException();

    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }

    }

    public synchronized void method1() {
        /*
        // 抛出Exception
        System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
            //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。
            throw new Exception();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "线程执行结束");
        */

        // 抛出RuntimeException
        System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。
        throw new RuntimeException();
        // System.out.println(Thread.currentThread().getName() + "线程执行结束");
    }

    public synchronized void method2() {
        System.out.println("我也是加锁的非静态方法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) throws InterruptedException {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("fininshed");
    }
}

运行结果:

我是加锁的静态方法1Thread-0
Exception in thread "Thread-0" java.lang.RuntimeException
	at com.interview.javabasic.thread.a0914.SynchronizedException.method1(SynchronizedException.java:50)
	at com.interview.javabasic.thread.a0914.SynchronizedException.run(SynchronizedException.java:16)
	at java.lang.Thread.run(Thread.java:748)
我也是加锁的非静态方法2Thread-1
Thread-1线程执行结束
fininshed

解析:方法抛出异常后,会释放锁。

总结:

  1. 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应第1、5种情况)
  2. 每一个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是 *.class 以及synchronized修饰的是static方法的时候,所有对象公用一把类锁(对应第2、3、4、6种情况)
  3. 无论方法正常执行完毕或者方法抛出异常,都会释放锁(对应第7种情况)。
  4. 目前进入被synchronized 的方法,在这方法里面调用没有synchronized修饰的方法。还是线程安全的吗?(不是线程安全的,出了synchronized,进入没有被synchronized修饰的方法,就可以同时被多个线程调用。)

参考文章:

不啰嗦,文章结束,建议三连!

标签:同步,Thread,getName,System,并发,println,多线程,public,out
来源: https://blog.csdn.net/qq_34272760/article/details/120298057

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有