synchronized二三事4

来源:互联网 发布:知乎中央民族大学舞蹈 编辑:程序博客网 时间:2024/06/04 18:53

1、synchronized static

是对当前*.Java中的Class类的锁定,虽然与非静态的有时候执行结果一样,但还是不同的,一个是对Class类持锁,一个是对象持锁。 线程AB是对类持锁,但C是Service对象持锁。AB是同步的,AC是异步的,synchronized static (object){...}也是如此

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(Exception e){e.printStackTrace();}}synchronized public static void printB(){try{System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 执行了printB方法");System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 退出了printB方法");}catch(Exception e){e.printStackTrace();}}synchronized public void printC(){System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 执行了printC方法");System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 退出了printC方法");}}public class Run extends Thread{private Service s;private int i;public Run(Service s,int i){super();this.s=s;this.i=i;}public void run(){if(i==0) s.printA();else if(i==1) s.printB();else s.printC();}public static void main(String[] args){Service s=new Service();Run r1=new Run(s,0);Run r2=new Run(s,1);Run r3=new Run(s,3);r1.setName("ThreadA");r2.setName("ThreadB");r3.setName("ThreadC");r1.start();r2.start();r3.start();}}

ThreadA在1490239424698 执行了printA方法ThreadC在1490239424698 执行了printC方法ThreadC在1490239424698 退出了printC方法ThreadA在1490239427698 退出了printA方法ThreadB在1490239427698 执行了printB方法ThreadB在1490239427698 退出了printB方法

2.常量池特性

public static void main(String[] args){String a="a";String b="a";System.out.println(a==b);
返回true

所以如果同步代码块中的对象是常量的String,而在两个线程中的run方法中都是调用 service.print("AA")虽然属于两个线程,但是是同一个object,即两个线程持有相同的锁,造成线程B不能执行。所以同步代码块的对象都不使用String对象。

3.内部类与同步

(1)代码块synchronized(class2)对class2对象获得锁,其他线程只能以同步的形式访问class2中的静态方法。

class Out{static class In1{public void method1(In2 in2){String name=Thread.currentThread().getName();synchronized(in2){//对In2的实例对象in2持有锁System.out.println(name+"进入到In1中的method1方法");for(int i=0;i<10;i++){System.out.println("i="+i);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In1中的method1方法");}}public synchronized void method2(){String name=Thread.currentThread().getName();System.out.println(name+"进入In1的method2方法中");for(int j=0;j<10;j++){System.out.println("j="+j);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In1中的method2方法");}}static class In2{//In1中的method1中对对象持有锁,所以下面的线程C收到阻塞synchronized public void method1(){String name=Thread.currentThread().getName();System.out.println(name+"进入In2中的method1方法");for(int k=0;k<10;k++){System.out.println("k="+k);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In2中的method1方法");}}}public class Run extends Thread{public static void main(String[] args){final Out.In1 in1=new Out.In1();final Out.In2 in2=new Out.In2();Thread r1=new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubin1.method1(in2);}});Thread r2=new Thread(new Runnable(){public void run(){in1.method2();}});Thread r3=new Thread(new Runnable(){public void run(){in2.method1();}});r1.setName("ThreadA");r2.setName("ThreadB");r3.setName("ThreadC");r1.start();r2.start();r3.start();}}

ThreadA进入到In1中的method1方法ThreadB进入In1的method2方法中j=0i=0j=1i=1i=2j=2j=3i=3i=4j=4j=5i=5i=6j=6i=7j=7j=8i=8j=9i=9ThreadA离开In1中的method1方法ThreadB离开In1中的method2方法ThreadC进入In2中的method1方法k=0k=1k=2k=3k=4k=5k=6k=7k=8k=9ThreadC离开In2中的method1方法

4.锁对象的改变

多个线程访问对象时一定要注意这些对象是否是同一个,如果不是就是各自获得各自对象的锁,以异步方式进行,只有同一个对象时才会以同步方式进行访问。但是要注意改变的是对象,而不是对象的属性,如果同步的对象是user对象,但是在线程中只改变user的name属性值,则两个线程实际上还是同步访问该user对象。

比如下列简化代码

class Task{private String s1="123";public void doLongTimeTask(){try{synchronized(s1){String name=Thread.currentThread().getName();System.out.println(name+" begin "+System.currentTimeMillis());s1="456";//修改了synchronized的对象Thread.sleep(2000);System.out.println(name+" end "+System.currentTimeMillis());}}catch(Exception e){e.printStackTrace();}}}
public static void main(String[] args){Task t=new Task();Thread r1=new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubt.doLongTimeTask();}});Thread r2=new Thread(new Runnable(){public void run(){t.doLongTimeTask();}});try {r1.setName("ThreadA");r2.setName("ThreadB");r1.start();Thread.sleep(50);//注意 sleep是使得String=456的,这样B线程的对象就是S1=456不是123,异步执行//若不加sleep那么B和A针对的是同一个对象,b发生阻塞,要等到a执行完才会获得对象锁r2.start();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}

ThreadA begin 1490252117538ThreadB begin 1490252117589ThreadA end 1490252119538ThreadB end 1490252119589



1 0
原创粉丝点击