java多线程系列四:synchronized

来源:互联网 发布:visual studio mac版 编辑:程序博客网 时间:2024/05/21 11:59
参考:http://www.cnblogs.com/skywang12345/p/3479202.html
主要四个知识点:
一:synchronized基本规则:
(1)当一个线程的“某对象”访问被synchronized修饰的“synchronized方法”或者“synchronized代码块"时,其他线程的“该对象” 的该”synchronized方法“后者”synchronized代码块“将被阻塞,但是不同对象对该“synchronized方法”或者“synchronized代码块”可以访问
(2)当一个线程的“某对象”访问被synchronized修饰的“synchronized方法”或者“synchronized代码块”时,其他线程的“该对象”仍然可以访问非synchronized修饰的方法或者代码块
(3)当一个线程的“某对象“访问被synchronized修饰的”synchronized方法“或者”synchronized代码块“时,其他线程的”改对象“对其他的”synchronized方法“或者”synchronized代码块“的访问将被阻塞
总结:其实就是说一个对象拥有一把同步锁,当这个同步锁被一个线程A获取到时,被synchronized修饰的所有方法或者代码块都不能被该对象的其他线程所访问,不管是针对线程A访问的“synchronized方法”或者“synchronized代码块”还是其他的“synchronized方法”或者“synchronized代码块”(每个对象有且仅有一把同步锁,同步锁依赖于对象存在而存在)
(1)当一个线程的“某对象”访问被synchronized修饰的“synchronized方法”或者“synchronized代码块"时,其他线程的“该对象” 的该”synchronized方法“后者”synchronized代码块“将被阻塞,但是不同对象对该“synchronized方法”或者“synchronized代码块”可以访问
看以下代码:
public class Mythread implements Runnable{public void run() {// TODO Auto-generated method stubsynchronized(this){for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+" loop  "+i);try {                     Thread.sleep(50);                } catch (InterruptedException ie) {                }  }}}}class Demo1_1{public static void main(String[] args){Runnable mr=new Mythread();Thread m1=new Thread(mr,"m1");Thread m2=new Thread(mr,"m2");m1.start();m2.start();}}
运行结果是:
m1 loop  0
m1 loop  1
m1 loop  2
m1 loop  3
m1 loop  4
m2 loop  0
m2 loop  1
m2 loop  2
m2 loop  3
m2 loop  4
因为这里m1,m2共用一个对象mr,所以两个线程共用一个同步锁

看下面代码:

public class Mythread implements Runnable{public void run() {// TODO Auto-generated method stubsynchronized(this){for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+" loop "+i);try { Thread.sleep(50); } catch (InterruptedException ie) { } }}}}class Demo1_1{public static void main(String[] args){Runnable mr=new Mythread();Runnable mr2=new Mythread();Thread m1=new Thread(mr,"m1");Thread m2=new Thread(mr2,"m2");m1.start();m2.start();}}

运行结果是:
m1 loop  0
m2 loop  0
m1 loop  1
m2 loop  1
m2 loop  2
m1 loop  2
m1 loop  3
m2 loop  3
m1 loop  4
m2 loop  4
这里我用了两个对象mr,mr2,意味着两把同步锁,所以体现出了并发
同理:

public class Mythread extends Thread{public void run() {// TODO Auto-generated method stubsynchronized(this){for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+" loop "+i);try { Thread.sleep(50); } catch (InterruptedException ie) { } }}}}class Demo1_1{public static void main(String[] args){Thread m1=new Mythread();Thread m2=new Mythread();m1.start();m2.start();}}

运行结果:
Thread-0 loop  0
Thread-1 loop  0
Thread-1 loop  1
Thread-0 loop  1
Thread-1 loop  2
Thread-0 loop  2
Thread-1 loop  3
Thread-0 loop  3
Thread-1 loop  4
Thread-0 loop  4
理解了前面两个这一个应该很好理解了哈~

(2)当一个线程的“某对象”访问被synchronized修饰的“synchronized方法”或者“synchronized代码块”时,其他线程的“该对象”仍然可以访问非synchronized修饰的方法或者代码块
看下面代码:

public class MythreadRun {public static void main(String[] args){final demo_02 demo=new demo_02();Thread m1=new Thread(new Runnable(){public void run(){demo.synMethod();}},"m1");Thread m2=new Thread(new Runnable(){public void run(){demo.nonsynMethod();}},"m2");m1.start();m2.start();}}class demo_02{public void synMethod(){synchronized(this){try {for(int i=0;i<5;i++){Thread.sleep(100);System.out.println(Thread.currentThread().getName()+" loop "+i);}} catch (Exception e) {// TODO: handle exception}}}public void nonsynMethod(){try {for(int i=0;i<5;i++){Thread.sleep(100);System.out.println(Thread.currentThread().getName()+" loop "+i);}} catch (Exception e) {// TODO: handle exception}}}

运行结果:
m1 loop 0
m2 loop 0
m1 loop 1
m2 loop 1
m1 loop 2
m2 loop 2
m1 loop 3
m2 loop 3
m1 loop 4
m2 loop 4
结果很明了,虽然是同一个对象,但是访问非synchronized修饰的代码块还是可以并发

(3)当一个线程的“某对象“访问被synchronized修饰的”synchronized方法“或者”synchronized代码块“时,其他线程的”该对象“的其他的”synchronized方法“或者”synchronized代码块“的访问将被阻塞
看以下代码:

class Count {public void synMethod(){ synchronized(this){ try { for (int i = 0; i < 5; i++) { Thread.sleep(100); System.out.println(Thread.currentThread().getName() + " loop " + i); } } catch (InterruptedException ie) { } } } public void nonsynMethod(){synchronized(this){ try { for (int i = 0; i < 5; i++) { Thread.sleep(100); System.out.println(Thread.currentThread().getName() + " loop " + i); } } catch (InterruptedException ie) { }}}}public class Demo{public static void main(String[] args){final Count count=new Count();Thread m1=new Thread(new Runnable(){public void run(){count.synMethod();}},"m1");Thread m2=new Thread(new Runnable(){public void run(){count.nonsynMethod();}},"m2");m1.start();m2.start();}}

运行结果:
m1 loop 0
m1 loop 1
m1 loop 2
m1 loop 3
m1 loop 4
m2 loop 0
m2 loop 1
m2 loop 2
m2 loop 3
m2 loop 4
只要是同一个对象,对应同一把同步锁,所有用synchronized修饰的方法和代码块都是互斥访问

二:synchronized方法和synchronized代码块
synchronized代码块比synchronized方法更加高效
这个我通过按照http://www.cnblogs.com/skywang12345/p/3479202.html这个博主的代码实验发现运行时间是一样的,暂时还不知道怎么证明

三:实例锁和全局锁
实例锁 -- 锁在某一个实例对象上。如果该类是单例,那么该锁也具有全局锁的概念。
               实例锁对应的就是synchronized关键字。
全局锁 -- 该锁针对的是类,无论实例多少个对象,那么线程都共享该锁。
               全局锁对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。
如果用了static synchronized修饰的方法或者代码块,那么不管实例多少个对象,对被修饰的“static synchronized方法”或者“static synchronized代码块”都是互斥的,全局只有一把同步锁

0 0