Java多线程synchronized同步

非线程安全问题

“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”。也即是说,方法中的变量永远是线程安全的。

如果多个线程共同访问1个对象中的实例变量,则可能线程不安全。下面以实例说明

 1 public class HasSelfNum {
 2     private int num = 0;
 3     public void add(String name) {
 4         try {
 5             if (name.equals("a")) {
 6                 num = 100;
 7                 System.out.println("a over");
 8                 Thread.sleep(1000);
 9             } else {
10                 num = 200;
11                 System.out.println("b over");
12             }
13             System.out.println(name+" "+num);
14         } catch (InterruptedException e) {
15             // TODO Auto-generated catch block
16             e.printStackTrace();
17         }
18     }
19 }
 1 public class ThreadA extends Thread{
 2     private HasSelfNum hasSelfNum;
 3     
 4     public ThreadA(HasSelfNum hasSelfNum) {
 5         this.hasSelfNum = hasSelfNum;
 6     }
 7     
 8     @Override
 9     public void run() {
10         super.run();
11         hasSelfNum.add("a");
12     }
13 }
 1 public class ThreadB extends Thread{
 2     private HasSelfNum hasSelfNum;
 3     
 4     public ThreadB(HasSelfNum hasSelfNum) {
 5         this.hasSelfNum = hasSelfNum;
 6     }
 7     
 8     @Override
 9     public void run() {
10         super.run();
11         hasSelfNum.add("b");
12     }
13 }
 1 public class Main {
 2     public static void main(String[] args) {
 3         HasSelfNum hasSelfNum = new HasSelfNum();
 4         ThreadA threadA = new ThreadA(hasSelfNum);
 5         ThreadB threadB = new ThreadB(hasSelfNum);
 6         
 7         threadA.start();
 8         threadB.start();
 9     }
10 }

Result

1 a over
2 b over
3 b 200
4 a 200
View Code
非线程安全!
如何处理?
在add方法上加上关键字 synchronized
synchronized public void add(String name)
Result
1 a over
2 a 100
3 b over
4 b 200
View Code

线程安全,同步访问add()方法

如果是多个对象的情况?

将上面的Main.java进行修改

 1 public class Main {
 2     public static void main(String[] args) {
 3         HasSelfNum hasSelfNum = new HasSelfNum();
 4         HasSelfNum hasSelfNum2 = new HasSelfNum(); //两个对象
 5         
 6         ThreadA threadA = new ThreadA(hasSelfNum);
 7         ThreadB threadB = new ThreadB(hasSelfNum2);
 8         
 9         threadA.start();
10         threadB.start();
11     }
12 }

Result

1 a over
2 b over
3 b 200
4 a 100
View Code
两个线程分别访问同一个类的不同实例的相同同步方法,产生了两个锁,运行的结果是异步的。
由此可以看出,关键字synchronized取得的锁是对象锁

 

若类中既有synchronized类型方法又有非synchronized类型方法

 1 public class MyObject {
 2     synchronized public void methodA(){
 3         try {
 4             System.out.println(Thread.currentThread().getName()+" begin");
 5             Thread.sleep(1000);
 6             System.out.println(Thread.currentThread().getName()+" end");
 7         } catch (InterruptedException e) {
 8             // TODO Auto-generated catch block
 9             e.printStackTrace();
10         }
11     }
12     
13     public void methodB(){
14         try {
15             System.out.println(Thread.currentThread().getName()+" begin");
16             Thread.sleep(1000);
17             System.out.println(Thread.currentThread().getName()+" end");
18         } catch (InterruptedException e) {
19             // TODO Auto-generated catch block
20             e.printStackTrace();
21         }
22     }
23         
24 }
 1 public class ThreadA extends Thread{
 2     MyObject myObject;
 3     public ThreadA(MyObject    myObject) {
 4         this.myObject = myObject;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         super.run();
10         myObject.methodA();
11     }
12 }
 1 public class ThreadB extends Thread{
 2     MyObject myObject;
 3     public ThreadB(MyObject    myObject) {
 4         this.myObject = myObject;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         super.run();
10         myObject.methodB();
11     }
12 }
 1 public class Main {
 2     public static void main(String[] args) {
 3         MyObject myObject = new MyObject();
 4         
 5         ThreadA threadA = new ThreadA(myObject);
 6         ThreadB threadB = new ThreadB(myObject);
 7         threadA.setName("A");
 8         threadB.setName("B");
 9         
10         threadA.start();
11         threadB.start();
12     }
13 }

Result

1 A begin
2 B begin
3 B end
4 A end
View Code
线程A持有myObject对象锁,但线程B仍可以异步调用非synchronized类型方法
当在methodB方法前也加上synchronized关键字时
Result
1 A begin
2 A end
3 B begin
4 B end
View Code

线程A、B以同步的方式执行对象中的两方法

synchronized同步代码块

synchronized修饰的方法里有个耗时很长的代码时,效率是很低的。同步代码块分为:
1.synchronized(this)
在方法中不在同步代码块中的代码异步执行,而在其中的代码同步执行
同个对象中的synchronized(this)使用的对象监视器是同一个,也就是说,当一个线程访问某个synchronized(this)代码块里面的方法时,其他线程访问其他synchronized(this)块里面的方法是会被阻塞的。另外synchronized(this)使用的监视器和syncheronized 修饰方法一致是当前对象,也会阻塞synchronized修饰的方法。
2.synchronized(obj) 非this
多个线程同时访问时只能阻塞synchronized(obj)的代码块。
同时如果锁是同一个myObject对象,还是会阻塞的
 1 public class MyObject {
 2     synchronized public void methodA() {
 3         try {
 4             System.out.println(Thread.currentThread().getName() + " begin");
 5             Thread.sleep(1000);
 6             System.out.println(Thread.currentThread().getName() + " end");
 7         } catch (InterruptedException e) {
 8             // TODO Auto-generated catch block
 9             e.printStackTrace();
10         }
11     }
12     public void methodB(MyObject myObject) {
13         synchronized (myObject) {
14             try {
15                 System.out.println(Thread.currentThread().getName() + " begin");
16                 Thread.sleep(1000);
17                 System.out.println(Thread.currentThread().getName() + " end");
18             } catch (InterruptedException e) {
19                 // TODO Auto-generated catch block
20                 e.printStackTrace();
21             }
22         }
23     }
24 }
 1 public class ThreadA extends Thread{
 2     MyObject myObject;
 3     public ThreadA(MyObject    myObject) {
 4         this.myObject = myObject;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         super.run();
10         myObject.methodA();
11     }
12 }
 1 public class ThreadB extends Thread{
 2     MyObject myObject;
 3     public ThreadB(MyObject    myObject) {
 4         this.myObject = myObject;
 5     }
 6     
 7     @Override
 8     public void run() {
 9         super.run();
10         myObject.methodB(myObject);
11     }
12 }
 1 public class Main {
 2     public static void main(String[] args) {
 3         MyObject myObject = new MyObject();
 4         
 5         ThreadA threadA = new ThreadA(myObject);
 6         ThreadB threadB = new ThreadB(myObject);
 7         threadA.setName("A");
 8         threadB.setName("B");
 9         
10         threadB.start();
11         threadA.start();
12     }
13 }

Result

1 B begin
2 B end
3 A begin
4 A end

《Java多线程编程核心技术》学习

原文地址:https://www.cnblogs.com/zhaoww/p/5827352.html