您的位置:首页 > 其它

synchronized 方法与锁对象

2016-03-15 23:16 274 查看
两个线程均调用共享对象的同步方法:

class MyObject{
public synchronized void methodA(){
System.out.println("begin methodA threadName= " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println("methodA end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class ThreadA extends Thread{
private MyObject object;

public ThreadA(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodA();
}
}

class ThreadB extends Thread{
private MyObject object;

public ThreadB(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodA();
}
}
public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B");
a.start();
b.start();
}
}


结果肯定是顺序执行:

begin methodA threadName= A
methodA end
begin methodA threadName= B
methodA end


A线程调用共享对象的同步方法,B线程调用共享对象非同步方法:

class MyObject{
public synchronized void methodA(){
System.out.println("begin methodA threadName= " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println("methodA end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void methodB(){
System.out.println("begin methodB threadName= " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println("methodB end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class ThreadA extends Thread{
private MyObject object;

public ThreadA(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodA();
}
}

class ThreadB extends Thread{
private MyObject object;

public ThreadB(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodB();
}
}
public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B");
a.start();
b.start();
}
}


结果是:

begin methodA threadName= A
begin methodB threadName= B
methodA end
methodB end


A线程调用共享对象的同步方法,B线程调用共享对象另一个同步方法

class MyObject{
public synchronized void methodA(){
System.out.println("begin methodA threadName= " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println("methodA end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public synchronized void methodB(){
System.out.println("begin methodB threadName= " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println("methodB end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class ThreadA extends Thread{
private MyObject object;

public ThreadA(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodA();
}
}

class ThreadB extends Thread{
private MyObject object;

public ThreadB(MyObject object){
this.object = object;
}

@Override
public void run() {
object.methodB();
}
}
public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B");
a.start();
b.start();
}
}


结果是:

begin methodA threadName= A
methodA end
begin methodB threadName= B
methodB end


结论:

1. A线程和B线程均调用object对象的synchronized方法,则必须是同步方式调用

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

3. A线程先持有object对象的Lock锁,B线程如果此时调用object对象中的synchronized类型的方法则需等待,即只能是同步方式调用

结论2即对应了脏读的现象:

比如赋值方法是同步,取值方法是非同步,则可能出现脏读,即在读取实例变量时,此值已经被其他线程更改过了

class MyObject{
private String username = "A";
private String password = "AA";

public synchronized void setValue(String username, String password){
this.username = username;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.password = password;
System.out.println("setValue username : " + username + " password : " + password);
}

public void getValue(){
System.out.println("getValue username : " + username + " password : " + password);
}
}

class ThreadA extends Thread{
private MyObject object;

public ThreadA(MyObject object){
this.object = object;
}

@Override
public void run() {
object.setValue("B", "BB");
}
}

public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
a.start();
try {
Thread.sleep(200);//结果受此值影响
} catch (InterruptedException e) {
e.printStackTrace();
}
object.getValue();
}
}


可对getValue添加synchronzied关键字修饰,避免脏读

当线程调用anyObject对象加入synchronized关键字修饰的X方法时,A线程就获得了X方法锁,更准确的讲是获得了anyObject对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,但是其他线程可以调用anyObject的其他非synchronized关键字修饰的方法。可若其他线程调用anyOjbect的其他synchronized关键字修饰的方法时,也必须等待A线程执行完毕,释放了对象锁后才可以调用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: