java 0l_Java Synchronized

本文详细探讨了Java中的`synchronized`关键字,包括同步方法和同步语句块的使用。通过实例展示了`synchronized`如何实现线程同步,以及锁重入功能。同时,解释了静态同步方法和`synchronized(this)`代码块的区别,强调了对象监视器的重要性。
摘要由CSDN通过智能技术生成

1、synchronized 同步方法:

是对当前对象加锁。

packagecom.test;public classTestObject {synchronized public voidmethodA() {try{

System.out.println("begin methodA threadName=" + Thread.currentThread().getName() + " beigin time = " +System.currentTimeMillis());

Thread.sleep(1000);

System.out.println("end methodA endTime=" +System.currentTimeMillis());

}catch(Exception e) {

e.printStackTrace();

}

}public voidmethodB() {try{

System.out.println("begin methodB threadName=" + Thread.currentThread().getName() + " beigin time = " +System.currentTimeMillis());

Thread.sleep(1000);

System.out.println("end methodB endTime=" +System.currentTimeMillis());

}catch(Exception e) {

e.printStackTrace();

}

}

}

packagecom.test;public classRun {public static voidmain(String[] args) {

TestObject object= newTestObject();

Thread a= new Thread(newRunnable() {

@Overridepublic voidrun() {

object.methodA();

}

});

Thread b= new Thread(newRunnable() {

@Overridepublic voidrun() {

object.methodB();

}

});

a.start();

b.start();

}

}

运行结果:

begin methodA threadName=Thread-0 beigin time = 1527756573018begin methodB threadName=Thread-1 beigin time = 1527756573018end methodB endTime=1527756574018end methodA endTime=1527756574018

通过上面的代码可以得知,虽然线程A先持有了object对象的锁,但是线程B完全可以异步调用非synchronized类型的方法。

如果将TestObject.java 中的methodB()方法前加上synchronized关键字。

#methodB()前加synchronized关键字运行结果:

begin methodA threadName=Thread-0 beigin time = 1527756647320end methodA endTime=1527756648321begin methodB threadName=Thread-1 beigin time = 1527756648321end methodB endTime=1527756649321

结论:

A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中非synchronized类型的方法。

A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。

总结:

关键字synchronized 拥有锁重入的功能,也就是在使用synchronized时,但一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。

同步不可以继承。

2、synchronized同步语句块:

是对某一个对象进行加锁。synchronized(this) 锁定的也是当前对象。

用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长的时间。在这样的情况下可以使用synchronized同步语句块来解决。

packagecom.test;public classTask {public voidmethodA() {try{synchronized (this) {

System.out.println("A begin time = " +System.currentTimeMillis());

Thread.sleep(2000);

System.out.println("A end time = " +System.currentTimeMillis());

}

}catch(Exception e) {

e.printStackTrace();

}

}public voidmethodB() {try{synchronized (this) {

System.out.println("B begin time = " +System.currentTimeMillis());

System.out.println("B end time = " +System.currentTimeMillis());

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

packagecom.test;public classRun {public static voidmain(String[] args) {

Task task= newTask();

Thread a= new Thread(newRunnable() {

@Overridepublic voidrun() {

task.methodA();

}

});

Thread b= new Thread(newRunnable() {

@Overridepublic voidrun() {

task.methodB();

}

});

a.start();

b.start();

}

}

运行结果:

A begintime = 1527757467600A endtime = 1527757469601B begintime = 1527757469601B endtime = 1527757469601

在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的 对象监视器 是一个。

将任意对象作为对象监视器:

多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的阻塞的。

packagecom.test;public classService {private String anyString = newString();public voidmethodA() {try{synchronized(anyString) {

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块");

Thread.sleep(3000);

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块");

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

packagecom.test;public classRun {public static voidmain(String[] args) {

Service service= newService();

Thread a= new Thread(newRunnable() {

@Overridepublic voidrun() {

service.methodA();

}

});

Thread b= new Thread(newRunnable() {

@Overridepublic voidrun() {

service.methodA();

}

});

a.start();

b.start();

}

}

运行结果:

线程名为:Thread-1在1527758321295进入同步块

线程名为:Thread-1在1527758324295离开同步块

线程名为:Thread-0在1527758324295进入同步块

线程名为:Thread-0在1527758327295离开同步块

使用 synchronized(非this对象x)同步代码块进行同步操作时,对象监视器必须是同一个对象。如果不是同一个对象,运行的结果就是异步了。

把Service.java修改为如下:

packagecom.test;public classService {private String anyString = newString();public voidmethodA() {try{synchronized(anyString) {

System.out.println("A begin");

Thread.sleep(3000);

System.out.println("A end");

}

}catch(Exception e) {

e.printStackTrace();

}

}synchronized public voidmethodB() {

System.out.println("B begin");

System.out.println("B end");

}

}

运行结果:

B begin

A begin

B end

A end

由于对象的监视器不同,所以运行结果就是异步的。

3、静态同步synchronized方法与synchronized(class)代码块:

关键字synchronized还可以应用在static静态方法上,如果这样写,那就是对当前的*.java文件对应的class类进行加锁。

packagecom.test;public classService {synchronized public static voidmethodA() {try{

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块");

Thread.sleep(3000);

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块");

}catch(InterruptedException e) {

e.printStackTrace();

}

}synchronized public static voidmethodB() {try{

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块");

Thread.sleep(3000);

System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块");

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

运行结果:

线程名为:Thread-1在1527758944286进入同步块

线程名为:Thread-1在1527758947287离开同步块

线程名为:Thread-0在1527758947287进入同步块

线程名为:Thread-0在1527758950287离开同步块

synchronized关键字加到static静态方法上是给Class上锁,而synchronized关键字加到非static静态方法上是给对象上锁。所以同一个类下使用两种加锁方式的方法是可以进行异步调用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值