java多线程-synchronized(二)

搬运文章

具体请看下面这位大佬的文章,写得真好
http://www.cnblogs.com/xrq730/p/4851350.html

一、线程访问不同的synchronized(this)

package java_lang_Object;

/**
 * Created by luckyboy on 2018/7/7.
 */
public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();
        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);
        Mythread_2 mythread_2 = new Mythread_2(threadDomain1);

        mythread_1.start();
        mythread_2.start();

    }
}

class ThreadDomain1{
    public void methodA(){
        //获得ThreadDomain1实例对象锁
        synchronized (this){
            System.out.println(Thread.currentThread().getName()+"进入了methodA的同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodA的同步代码块");
        }
    }
    public void methodB(){
        //获得ThreadDomain1实例对象锁
        synchronized (this){
            System.out.println(Thread.currentThread().getName()+"进入了methodB的同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodB的同步代码块");
        }
    }

}

//线程类1访问ThreadDomain1的methodA
class Mythread_1 extends Thread{
    private ThreadDomain1 threadDomain1;
    public Mythread_1(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }
    @Override
    public void run(){
        this.threadDomain1.methodA();
    }
}
//线程类2访问ThreadDomain1的methodB
class Mythread_2 extends Thread{
    private ThreadDomain1 threadDomain1;
    public Mythread_2(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }
    @Override
    public void run(){
        this.threadDomain1.methodB();
    }
}

输出结果

Thread-0进入了methodA的同步代码块
Thread-0休息了2s后退出methodA的同步代码块
Thread-1进入了methodB的同步代码块
Thread-1休息了2s后退出methodB的同步代码块

结果分析:我们看到Thread-0和Thread-1是有序的执行的,这是因为两个线程使用的是同一个对象,这个时候,一旦Thread-0进入了同步代码块,就会获得ThreadDomain的实例对象锁,Thread-1只能等待。

结论:对于一个synchronized(this)同步代码块,如果两个线程分别访问两个不同的synchronized(this),那么此时也是同步的。

二、线程访问同一个synchronized(this)

1、两个线程使用同一个对象

public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();
        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);
        Mythread_1 mythread_01 = new Mythread_1(threadDomain1);

        mythread_1.start();
        mythread_01.start();
    }
}

输出结果

Thread-0进入了methodA的同步代码块
Thread-0休息了2s后退出methodA的同步代码块
Thread-1进入了methodA的同步代码块
Thread-1休息了2s后退出methodA的同步代码块

2、两个线程使用不同的对象

public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();
        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);

        ThreadDomain1 threadDomain2 = new ThreadDomain1();
        Mythread_1 mythread_01 = new Mythread_1(threadDomain2);

        mythread_1.start();
        mythread_01.start();

    }
}

输出结果

Thread-1进入了methodA的同步代码块
Thread-0进入了methodA的同步代码块
Thread-0休息了2s后退出methodA的同步代码块
Thread-1休息了2s后退出methodA的同步代码块
结论
  • 如果两个线程使用同一个对象,两个线程访问同一个synchronized(this),那么每次只允许一个线程执行,线程同步
  • 如果两个线程使用不同的对象,两个线程访问同一个synchronized(this),那么线程可以同时访问这个代码块,线程异步

二、synchronized方法和synchronized(this)

class ThreadDomain1{
    public void methodA(){
        synchronized (this){
            System.out.println(Thread.currentThread().getName()+"进入了methodA的同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodA的同步代码块");
        }
    }


    public synchronized void methodC(){
        System.out.println(Thread.currentThread().getName()+"进入了methodC的同步方法");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodC的同步方法");
    }
}
//Mythread_1调用同步代码块synchronized(this)
class Mythread_1 extends Thread{
    private ThreadDomain1 threadDomain1;
    public Mythread_1(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }
    @Override
    public void run(){
        this.threadDomain1.methodA();
    }
}
//Mythread_3调用synchronized同步方法
class Mythread_3 extends Thread{
    private ThreadDomain1 threadDomain1;
    public Mythread_3(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }
    @Override
    public void run(){
        this.threadDomain1.methodC();
    }
}

1、测试代码:两个线程使用相同的对象,一个访问synchronized方法,一个访问synchronized(this){}

package java_lang_Object;

/**
 * Created by luckyboy on 2018/7/7.
 */
public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();
        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);

        Mythread_3 mythread_3 = new Mythread_3(threadDomain);

        mythread_1.start();
        mythread_3.start();

    }
}

输出结果

Thread-0进入了methodA的同步代码块
Thread-0休息了2s后退出methodA的同步代码块
Thread-1进入了methodC的同步方法
Thread-1休息了2s后退出methodC的同步方法

2、测试代码:两个线程使用不同的对象,一个访问synchronized方法,一个访问synchronized(this){}

package java_lang_Object;

/**
 * Created by luckyboy on 2018/7/7.
 */
public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();
        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);
        ThreadDomain1 threadDomain2 = new ThreadDomain1();
        Mythread_3 mythread_3 = new Mythread_3(threadDomain2);

        mythread_1.start();
        mythread_3.start();

    }
}

输出结果

Thread-0进入了methodA的同步代码块
Thread-1进入了methodC的同步方法
Thread-0休息了2s后退出methodA的同步代码块
Thread-1休息了2s后退出methodC的同步方法
结论
  • 如果两个线程使用同一个对象,一个访问synchronized方法,另一个访问synchronized(this){},那么两个线程是同步的。
  • 如果两个线程使用不同的对象,一个访问synchronized方法,另一个访问synchronized(this){},那么两个线程是异步的

三、synchronized静态方法和synchronized(this){}

class ThreadDomain1{
    public void methodA(){
        synchronized (this){
            System.out.println(Thread.currentThread().getName()+"进入了methodA的同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodA的同步代码块");
        }
    }

    public synchronized static void methodD(){
        System.out.println(Thread.currentThread().getName()+"进入了methodD的同步静态同步方法");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"休息了2s后退出methodC的静态同步方法");
    }
}
class Mythread_1 extends Thread{
    private ThreadDomain1 threadDomain1;
    public Mythread_1(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }
    @Override
    public void run(){
        this.threadDomain1.methodA();
    }
}

class Mythread_4 extends Thread{
    /*private ThreadDomain1 threadDomain1;
    public Mythread_4(ThreadDomain1 threadDomain1){
        this.threadDomain1 = threadDomain1;
    }*/
    @Override
    public void run(){
        ThreadDomain1.methodD();
    }
}

1、测试

package java_lang_Object;

/**
 * Created by luckyboy on 2018/7/7.
 */
public class SynchronizedTest_II {
    public static void main(String[] args){
        ThreadDomain1 threadDomain1 = new ThreadDomain1();

        Mythread_1 mythread_1 = new Mythread_1(threadDomain1);
        Mythread_4 mythread_4 = new Mythread_4();

        mythread_1.start();
        mythread_4.start();
    }
}

输出结果

Thread-0进入了methodA的同步代码块
Thread-1进入了methodD的同步静态同步方法
Thread-0休息了2s后退出methodA的同步代码块
Thread-1休息了2s后退出methodC的静态同步方法
结论
  • 两个线程使用同一个对象(静态方法不需要使用对象),一个访问synchronized修饰的静态方法,另一个访问synchronized(this){},线程是不同步的,更不用说两个线程使用不同线程的情况

总结

  • 如果两个线程一个访问synchronized修饰的静态方法,另一个访问synchronized(this){};那么两个线程是异步执行的
  • 如果两个线程使用不同的对象的情况下,两个线程访问的是不同对象的方法,这个时候线程之间是异步的
  • 如果两个线程使用相同的对象的情况下,两个线程不管是同时访问同一个synchronized(this){},还是同时访问synchronized()方法、或者是一个访问synchronized(this){} 而另一个访问synchronized();此时都会发生阻塞的情况

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/80949576