对象锁
synchronized修饰非静态方法
测试1:
public class Run {
public static void main(String[] args) {
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef);
athread.start();
ThreadB bthread = new ThreadB(numRef);
bthread.start();
}}
class HasSelfPrivateNum {
private int num = 0;
public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadA extends Thread {
private HasSelfPrivateNum numRef;
public ThreadA(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
}
@Override
public void run() {
super.run();
numRef.addI("a");
}
}
class ThreadB extends Thread {
private HasSelfPrivateNum numRef;
public ThreadB(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
}
@Override
public void run() {
super.run();
numRef.addI("b");
}
}
运行结果为:
a set over!
b set over!
b num=200
a num=200
修改HasSelfPrivateNum如下,方法用synchronized修饰如下:
class HasSelfPrivateNum {
private int num = 0;
synchronized public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果是线程安全的:
b set over!
b num=200
a set over!
a num=100
接着,我在main方法中做了修改,让2个线程对象的入参不再是同一个HasSelfPrivateNum对象,即
运行结果为:
修改HasSelfPrivateNum如下,方法用synchronized修饰如下:
运行结果是线程安全的:
接着,我在main方法中做了修改,让2个线程对象的入参不再是同一个HasSelfPrivateNum对象,即
测试2:
public static void main(String[] args) {
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef);
athread.start();
ThreadB bthread = new ThreadB(numRef2);
bthread.start();
}
结果是
a set over!
b set over!
b num=200
a num=100
原因是:因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系,因此,出现非同步的结果
接下来--
猜测A,它锁定了同一个对象,让这个对象在同一个时间只能在一个线程中使用,而其他的线程要等该对象被释放后,才等调用该变量?
猜测B:他仅仅限制了其他线程中这个对象调用与之相同的syncronized修饰的方法的权利?
猜测C:他仅仅限制了其他线程中这个对象调用syncronized修饰的方法的权利?
测试:在测试1的基础上 HasSelfPrivateNum类加入
public void addI2(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(4000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
修改threadB
class ThreadB extends Thread {
private HasSelfPrivateNum numRef;
public ThreadB(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
}
@Override
public void run() {
super.run();
// numRef.addI("b");
numRef.addI2("b"); //调用了addI2
}
}
结果是:
a set over!
b set over!
b num=200
a num=200
接着又在addI2上加上syncronized
结果是:
a set over!
a num=100
b set over!
b num=200
结论是:他仅仅限制了其他线程中这个对象调用syncronized修饰的方法的权利.
实验结论:
在方法上加syncronized,那当有一个线程运行一个对象的syncronized修饰的方法时,其他的线程无法运行该对象的syncronized修饰的方法,只要该线程对该对象的使用完毕时,其他线程才能使用该对象的yncronized修饰的方法;注意:是可以运行该对象那些没有被syncronized修饰的方法的
synchronized (this)
我们先看看代码实例(Run.java)
package com.demo.syncronyzed;
public class Run2 {
public static void main(String[] args) {
ObjectService service = new ObjectService();
Thread1 a = new Thread1(service);
a.setName("a");
a.start();
Thread2 b = new Thread2(service);
b.setName("b");
b.start();
}
}
class ObjectService {
public void serviceMethod() {
try {
synchronized (this) {
System.out.println("begin time=" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("end end=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Thread1 extends Thread {
private ObjectService service;
public Thread1(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethod();
}
}
class Thread2 extends Thread {
private ObjectService service;
public Thread2(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethod();
}
}
运行结果:
这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。
修改了
class ObjectService {
public void serviceMethod() {
try {
System.out.println("我是在同步代码块之前的,执行我的线程是"+Thread.currentThread().getName());
synchronized (this) {
System.out.println( Thread.currentThread().getName()+": begin time=" + System.currentTimeMillis());
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName()+": end end=" + System.currentTimeMillis());
}
System.out.println("我是在同步代码块之后的,执行我的线程是"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果是
我是在同步代码块之前的,执行我的线程是a
a: begin time=1520872280701
我是在同步代码块之前的,执行我的线程是b
a: end end=1520872284702
我是在同步代码块之后的,执行我的线程是a
b: begin time=1520872284702
b: end end=1520872288703
我是在同步代码块之后的,执行我的线程是b
结论是:
synchronized (){}的{}前后的代码依旧是异步的
class ObjectService加入了
public void serviceMethod2() {
try {
synchronized (this) {
System.out.println( Thread.currentThread().getName()+": begin time=" + System.currentTimeMillis());
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName()+": end end=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class Thread2 修改
public void run() {
super.run();
//service.serviceMethod();
service.serviceMethod2();
}
结果是:
a: begin time=1520872632945
a: end end=1520872636946
b: begin time=1520872636946
b: end end=1520872640947
接着将上面加入方法的 synchronized (this)去掉
结果是
a: begin time=1520872837388
b: begin time=1520872837388
a: end end=1520872841388
b: end end=1520872841388
总结
synchronized (this),当有一个线程运行一个对象的synchronized (this)修饰的代码块时,其他的线程无法运行该对象的synchronized (this)修饰的代码块,只有该线程对该代码块的运行完毕时,其他线程才能使用该对象的synchronized (this)修饰的代码块;注意:是可以运行该对象那些没有被synchronized (this)的代码块的,synchronized (){}的{}前后的代码依旧是异步的
synchronized (非this对象)
package com.demo.syncronyzed;
public class Run {
public static void main(String[] args) {
Service service = new Service("程序员");
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
}
class Service {
String anyString = new String();
public Service(String anyString){
this.anyString = anyString;
}
public void setUsernamePassword(String username, String password) {
try {
synchronized (anyString) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入同步块");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开同步块");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.setUsernamePassword("a", "aa");
}
}
class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.setUsernamePassword("b", "bb");
}
}
结果:
线程名称为:A在1520873855721进入同步块
线程名称为:A在1520873858723离开同步块
线程名称为:B在1520873858723进入同步块
线程名称为:B在1520873861723离开同步块
不难看出,这里线程争夺的是anyString的对象锁,两个线程有竞争同一对象锁的关系,出现同步
类锁
synchronized修饰静态方法
package com.demo.syncronyzed;
public class Run {
public static void main(String[] args) {
ThreadA a = new ThreadA();
a.setName("A");
a.start();
ThreadB b = new ThreadB();
b.setName("B");
b.start();
}
}
class Service {
synchronized public static void printA() {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public static void printB() {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
}
}
class ThreadA extends Thread {
@Override
public void run() {
Service.printA();
}
}
class ThreadB extends Thread {
@Override
public void run() {
Service.printB();
}
}
结果
线程名称为:A在1520874448288进入printA
线程名称为:A在1520874451288离开printA
线程名称为:B在1520874451288进入printB
线程名称为:B在1520874451288离开printB
两个线程在争夺同一个类锁,因此同步,类锁方式与sycronized修饰方法,不同是,它修饰的是静态方法;当线程执行被sycrinized修饰的静态方法时,其他的线程如果也要sycrinized修饰的静态方法执行,就需要等待.可以运行该对象那些没有被**syncronized修饰的方法的**.这和sycronized修饰方法类似;
synchronized (类名.class)
package com.demo.syncronyzed;
public class Run {
public static void main(String[] args) {
ThreadA a = new ThreadA();
a.setName("A");
a.start();
ThreadB b = new ThreadB();
b.setName("B");
b.start();
}
}
class Service {
public static void printA() {
synchronized (Service.class) {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void printB() {
synchronized (Service.class) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
}
}
}
class ThreadA extends Thread {
@Override
public void run() {
Service.printA();
}
}
class ThreadB extends Thread {
@Override
public void run() {
Service.printB();
}
}
结果是:
线程名称为:A在1520875240022进入printA
线程名称为:A在1520875243022离开printA
线程名称为:B在1520875243022进入printB
线程名称为:B在1520875243022离开printB
两个线程依旧在争夺同一个类锁,因此同步
加一个
public void printC() {
synchronized (this) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
}
}
修改一下ThreadB
class ThreadB extends Thread {
@Override
public void run() {
Service service=new Service();
service.printC();
}
结果是:
线程名称为:A在1520875593894进入printA
线程名称为:B在1520875593894进入printB
线程名称为:B在1520875593894离开printB
线程名称为:A在1520875596894离开printA
说明了:
对于同一个类A,线程1争夺A对象实例的对象锁,线程2争夺类A的类锁,这两者不存在竞争关系。也就说对象锁和类锁互补干预内政;
synchronized ---锁
猜你喜欢
转载自blog.csdn.net/weiqiang_java/article/details/79534862
今日推荐
周排行