天天看点

多个线程访问不同的synchronized方法

多个线程访问同一个synchronized方法,只有一个线程能够进入该方法。如果多个线程访问一个对象不同的synchronized方法呢?还是只有一个能进入吗?

下面验证一下:

package volatile1;

import java.util.concurrent.CountDownLatch;

/**
 * Created by sxb-gt on 2018/1/21.
 * “主线程类”注意:该类并没有集成Thread。只是为了形象,才取的这个名字。
 */
public class MainThread2 {
    private Integer i = 0;
    public synchronized void syn1() {
        System.out.println(Thread.currentThread().getName()+":" + "进入syn1");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":" + "执行完syn1");
    }
    public  synchronized void syn2() {
        System.out.println(Thread.currentThread().getName()+":" + "进入syn2");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":" + "执行完syn2");
    }
    public static void main(String[] args) {
        MainThread2 mainThread = new MainThread2();
        AssistantThread2 at2 = new AssistantThread2(mainThread);
        AssistantThread3 at3 = new AssistantThread3(mainThread);
        at2.start();
        at3.start();
    }
}
           
package volatile1;

import sun.applet.Main;

/**
 * Created by sxb-gt on 2018/1/21.
 */
public class AssistantThread2 extends Thread{
    private MainThread2 mainThread;
    public AssistantThread2(MainThread2 mainThread) {
        this.mainThread = mainThread;
    }
    @Override
    public void run() {
        mainThread.syn1();
    }
}
           
package volatile1;

/**
 * Created by sxb-gt on 2018/1/21.
 */
public class AssistantThread3 extends Thread{
    private MainThread2 mainThread;
    public AssistantThread3(MainThread2 mainThread) {
        this.mainThread = mainThread;
    }
    @Override
    public void run() {
        mainThread.syn2();
    }
}
           

执行结果:

Thread-0:进入syn1
Thread-0:执行完syn1
Thread-1:进入syn2
Thread-1:执行完syn2
           

总结:第二个线程是在第一个线程完全执行完之后才执行的。所以,方法上面加上synchronized锁住的是当前对象,所以同一时间只有一个线程能够访问对象中的其中一个synchronized方法。对于非synchronized方法,则没有限制。

接下来,调整下syn2去掉synchronized

public   void syn2() {
        System.out.println(Thread.currentThread().getName()+":" + "进入syn2");
        System.out.println(Thread.currentThread().getName()+":" + "执行完syn2");
    }
           

执行结果:

Thread-0:进入syn1
Thread-1:进入syn2
Thread-1:执行完syn2
Thread-0:执行完syn1
           

总结:非synchronized方法可以随意访问,不受限制。

那么同步代码块呢?如果一个线程先访问了synchronized方法,另一个线程可以访问同步代码块吗?接下来验证一下:

调整syn2方法如下:

public   void syn2() {
        System.out.println(Thread.currentThread().getName()+":" + "进入syn2");
        synchronized (this) {
            System.out.println("进入同步代码块");
        }
        System.out.println(Thread.currentThread().getName()+":" + "执行完syn2");
    }
           

执行结果:

Thread-0:进入syn1
Thread-1:进入syn2
Thread-0:执行完syn1
进入同步代码块
Thread-1:执行完syn2
           

结论:可以看到输出结果中,只有syn1执行完后,才进入syn2。其实 这里要注意的是,synchronized括号里面的是this,代表的是这个对象。线程需要拿到对象的锁,才可以进入同步代码块。因此效果和同步方法类似。如果synchronized括号后面不写this效果会怎样呢?

调整syn2方法如下:

public   void syn2() {
        System.out.println(Thread.currentThread().getName()+":" + "进入syn2");
        synchronized (i) {
            System.out.println("进入同步代码块");
        }
        System.out.println(Thread.currentThread().getName()+":" + "执行完syn2");
    }
           

执行结果:

Thread-0:进入syn1
Thread-1:进入syn2
进入同步代码块
Thread-1:执行完syn2
Thread-0:执行完syn1
           

总结:只要synchronized后面的括号中不是this,就可以进入同步代码块。

继续阅读