1.synchronized锁重入java
public class Service { synchronized public void service1(){ System.out.println("service1"); service2(); } synchronized public void service2(){ System.out.println("service2"); service3(); } synchronized public void service3(){ System.out.println("service2"); } }
//线程类 public class MyThread extends Thread{ @Override public void run() { Service service=new Service(); service.service1(); } }
//测试类
public class Run { public static void main(String[] args) { MyThread thread=new MyThread(); thread.start(); } /* output: service1 service2 service3 */ }
总结:本身能够再次获取本身的内部锁.也支持在父子类继承的环境中dom
2.出现异常,锁自动释放异步
public class Service { synchronized public void testMethod(){ if(Thread.currentThread().getName().equals("a")){ System.out.println("ThreadName="+Thread.currentThread().getName() +" run beginTime="+System.currentTimeMillis()); int i=1; while(i==1){ if((""+Math.random()).substring(0,8).equals("0.123456")){ System.out.println("ThreadName="+Thread.currentThread().getName() +" run exceptionTime="+System.currentTimeMillis()); Integer.parseInt("a"); } } }else{ System.out.println("Thread B runt Time="+System.currentTimeMillis()); } } }
public class Test { public static void main(String[] args) { try { Service service=new Service(); ThreadA a=new ThreadA(service); a.setName("a"); a.start(); Thread.sleep(500); ThreadB b=new ThreadB(service); b.setName("b"); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } } /*output: ThreadName=a run beginTime=1523554493390 ThreadName=a run exceptionTime=1523554494218 //a报错,锁自动释放 Thread B runt Time=1523554494219 Exception in thread "a" java.lang.NumberFormatException: For input string: "a" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:580) at java.lang.Integer.parseInt(Integer.java:615) at us.codecraft.dxc.Service.testMethod(Service.java:16) at us.codecraft.dxc.ThreadA.run(ThreadA.java:36) */ }
3.同步不具备继承性ide
//父类 public class Main { synchronized public void serviceMethod(){ try { System.out.println("int main 下一步 sleep begin threadName=" +Thread.currentThread().getName()+" time="+System.currentTimeMillis() ); Thread.sleep(5000); System.out.println("int main 下一步 sleep end threadName="+ Thread.currentThread().getName()+" time="+ System.currentTimeMillis() ); } catch (InterruptedException e) { e.printStackTrace(); } } }
//子类 public class Sub extends Main{ @Override public void serviceMethod() { try { System.out.println("int sub 下一步 sleep begin threadName=" +Thread.currentThread().getName()+" time="+System.currentTimeMillis() ); Thread.sleep(5000); System.out.println("int sub 下一步 sleep end threadName="+ Thread.currentThread().getName()+" time="+ System.currentTimeMillis() ); super.serviceMethod(); } catch (InterruptedException e) { e.printStackTrace(); } } }
//线程A public class ThreadA extends Thread{ private Sub sub; public ThreadA(Sub sub){ super(); this.sub=sub; } @Override public void run() { sub.serviceMethod(); } }
//线程B public class ThreadB extends Thread{ private Sub sub; public ThreadB(Sub sub){ super(); this.sub=sub; } @Override public void run() { sub.serviceMethod(); } }
public class Test { public static void main(String[] args) { Sub subRef=new Sub(); ThreadA a=new ThreadA(subRef); a.setName("A"); a.start(); ThreadB b=new ThreadB(subRef); b.setName("B"); b.start(); } /*output: int sub 下一步 sleep begin threadName=B time=1523556610729 int sub 下一步 sleep begin threadName=A time=1523556610729 int sub 下一步 sleep end threadName=A time=1523556615729 int sub 下一步 sleep end threadName=B time=1523556615729 int main 下一步 sleep begin threadName=A time=1523556615729 int main 下一步 sleep end threadName=A time=1523556620730 int main 下一步 sleep begin threadName=B time=1523556620730 int main 下一步 sleep end threadName=B time=1523556625730 */ }
4.synchronized的弊端:测试
package us.codecraft.dxc; /** * Created by Administrator on 2018/4/13. */ public class Task { private String getDate1; private String getDate2; public synchronized void doLongTimeTask(){ try { System.out.println("begin task"); Thread.sleep(3000); getDate1="长时间处理任务后从远程返回值1 threadName="+Thread.currentThread().getName(); getDate2="长时间处理任务后从远程返回值2 threadName="+Thread.currentThread().getName(); System.out.println(getDate1); System.out.println(getDate2); System.out.println("end task"); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class CommonUtils { public static long beginTime1; public static long endTime1; public static long beginTime2; public static long endTime2; }
public class MyThread1 extends Thread{ private Task task; public MyThread1(Task task){ super(); this.task=task; } @Override public void run() { super.run(); CommonUtils.beginTime1=System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime1=System.currentTimeMillis(); } }
public class MyThread2 extends Thread{ private Task task; public MyThread2(Task task){ super(); this.task=task; } @Override public void run() { super.run(); CommonUtils.beginTime2=System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime2=System.currentTimeMillis(); } }
public class Run { public static void main(String[] args) { Task task=new Task(); MyThread1 thread1=new MyThread1(task); thread1.start(); MyThread2 thread2=new MyThread2(task); thread2.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } long beginTime=CommonUtils.beginTime1; if(CommonUtils.beginTime2<CommonUtils.beginTime1){ beginTime=CommonUtils.beginTime2; } long endTime=CommonUtils.endTime1; if (CommonUtils.endTime2>CommonUtils.endTime1) { endTime = CommonUtils.endTime2; } System.out.println("耗时"+((endTime-beginTime)/1000)); } /*output: begin task 长时间处理任务后从远程返回值1 threadName=Thread-0 长时间处理任务后从远程返回值2 threadName=Thread-0 end task begin task 长时间处理任务后从远程返回值1 threadName=Thread-1 长时间处理任务后从远程返回值2 threadName=Thread-1 end task 耗时6*/ }
一段时间内只能有一个线程被执行,另外一个线程必须等待当前线程执行完代码之后才能执行该代码块this
解决方法:使用同步代码块线程
public class Task { private String getDate1; private String getDate2; public void doLongTimeTask(){ try { System.out.println("begin task"); Thread.sleep(3000); synchronized (this){ getDate1="长时间处理任务后从远程返回值1 threadName="+Thread.currentThread().getName(); getDate2="长时间处理任务后从远程返回值2 threadName="+Thread.currentThread().getName(); } System.out.println(getDate1); System.out.println(getDate2); System.out.println("end task"); } catch (InterruptedException e) { e.printStackTrace(); } } /**output: begin task begin task 长时间处理任务后从远程返回值1 threadName=t1 长时间处理任务后从远程返回值2 threadName=t1 end task 长时间处理任务后从远程返回值1 threadName=t2 长时间处理任务后从远程返回值2 threadName=t2 end task 耗时3 / }
5.多个线程调用同一个对象中的不一样名称的synchronized同步方法或者synchronized(this)同步代码块时,调用的效果是按照顺序执行,也就是同步的,阻塞的code
synchronized同步方法和synchronized(this)同步代码块分别有两种做用:orm
对其余synchronized同步方法或者synchronized(this)同步代码块调用呈阻塞状态对象
同一时间只有一个线程能够执行或者synchronized()同步方法或者synchronized(this)同步代码中的代码
6.将任意对象做为对象监视器
public class Service { private String password; private String username; String anyString =new String(); public void setUsernamePass(String username,String password){ try { synchronized (anyString) { System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); Thread.sleep(3000); this.username = username; this.password=password; System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class ThreadA extends Thread{ private Service service; public ThreadA(Service service){ super(); this.service=service; } @Override public void run() { service.setUsernamePass("a","aa"); } }
public class ThreadB extends Thread{ private Service service; public ThreadB(Service service){ super(); this.service=service; } @Override public void run() { service.setUsernamePass("b","bb"); } }
public class Run { public static void main(String[] args) throws InterruptedException { Service service=new Service(); ThreadA threadA=new ThreadA(service); threadA.setName("A"); threadA.start(); ThreadB threadB=new ThreadB(service); threadB.setName("B"); threadB.start(); } /*output: 线程名为:A在1522229473958进入同步块 线程名为:A在1522229476969离开同步块 线程名为:B在1522229476969进入同步块 线程名为:B在1522229479980离开同步块 //同步,阻塞,先由A进入,再由B进入 */ }
总结:咱们能够看出synchronized(非this对象)若是是公共资源(调用同一个类对象,两个线程影响同一个anyString)就是实现同步,阻塞功能.由此咱们能够得出,若是synchronized(非this对象)锁住的是私有变量的话,就能够实现异步,非阻塞的功能,下面咱们来实验一下.
public class Service { private String password; private String username; public void setUsernamePass(String username,String password){ try { String anyString =new String();//将变量设置为局部变量 synchronized (anyString) { System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); Thread.sleep(3000); this.username = username; this.password=password; System.out.println("线程名为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } } catch (InterruptedException e) { e.printStackTrace(); } } /*output: 线程名为:A在1522229832397进入同步块 线程名为:B在1522229832397进入同步块 线程名为:A在1522229835408离开同步块 线程名为:B在1522229835408离开同步块 //两个线程同时进入方法,非阻塞,异步 */ }
总结:大大提升了运行效率.
7.静态同步synchronized方法与synchronized(class)代码块
synchronized应用在static静态方法上,这样是对当前的*.class文件对应的class类进行持锁.
例子:
public 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"); } }
public class ThreadA extends Thread{ @Override public void run() { Service.printA(); } }
public class ThreadB extends Thread{ @Override public void run() { Service.printB(); } }
public class Run { public static void main(String[] args) throws InterruptedException { ThreadA a =new ThreadA(); a.setName("a"); a.start(); ThreadB b=new ThreadB(); b.setName("b"); b.start(); } /*output: 线程名称为:a在1515601919412进入printA 线程名称为:a在1515601922412离开printA 线程名称为:b在1515601922412进入printB 线程名称为:b在1515601922412离开printB */ }
总结:synchronized关键字加到static静态方法上是给class类上锁,而synchronized关键字加到非static静态方法上是给对象加锁