线程安全:当多个线程访问某一个类时,这个类始终都能表现出正确的行为,那么这个类就是线程安全的ajax
synchronized: 能够在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或者“临界区”安全
private int count = 5; public synchronized void run(){ count--; System.err.println(this.currentThread().getName()+" count = "+count); }
当多个线程访问Thread的run()方法时,以排队的形式进行处理(排队是按照CPU分配的前后顺序而定的),一个线程要执行synchronized 修饰的方法里面的代码
1.尝试得到锁
2.若是拿到锁 执行synchronized 代码块内容 。若是拿不到锁 这个线程就会不断的尝试得到这把锁,直到拿到为止。并且多个线程同时去竞争这把锁,也就是会有锁竞争的问题异步
多个线程多个锁:每一个线程均可以拿到本身的指定的锁,分别拿到锁之后执行synchronized方法体里面的内容。async
synchronized关键字取得的锁都是对象锁 而不是把一段代码(方法)当成锁。
多个线程对象得到不一样的锁 他们互不影响。优化
private static int num; public static synchronized void printNum(String tag){ try{ if(tag.equals("a")){ num =100; System.err.println(" tag a"); Thread.sleep(2000); } else{ num = 200; System.err.println("tag b"); } } catch(Exception e){ e.printStackTrace(); } }
在静态方法上面加synchronized 关键字 表示锁定class类,独占class类,类级别的锁this
同步:synchronized 同步的概念就是共享。若是不共享资源,没有必须进行同步线程
异步:asynchronized 异步就是独立,相互之间不受制约。例如ajax请求设计
public synchronized void method1(){ try { System.err.println(Thread.currentThread().getName()); Thread.sleep(4000); } catch (Exception e) { e.printStackTrace(); } } public void method2(){ System.err.println(Thread.currentThread().getName()); }
1.a线程先持有Object对象的lock锁 B线程若是在这个时候调用对象中的synchronized 方法则须要等待 ,也就是同步。
2.a线程先持有Object对象的lock锁 B线程能够以异步的方式调用线程对象中的非synchronized 修饰的方法 ,不须要等待。日志
同步的目的是为了线程安全,对于线程安全须要知足2个特性code
脏读:在设计咱们的程序的时候必定要考虑到问题的总体性,否则就会出现很经典的错误:脏读
public synchronized void setValue(String username, String password){ this.username = username; this.password = password; try{ Thread.sleep(2000); }catch(Exception e){ e.printStackTrace(); } System.err.println("setValue的最终结果是 username "+ username+",password"+password); } public void getValue(){ System.err.println("getValue方法获得username"+ username+",password"+password); }
在对一个对象的方法加锁时候,须要考虑到业务的总体性,即在setValue/getValue方法同时加上synchronized 关键字保证业务的原子性
锁重入:当一个线程得到一个对象的锁之后 ,再次请求此对象时能够再次得到对象的锁
static class Main { public int i = 10; public synchronized void operationSup(){ try { i--; System.out.println("Main print i = " + i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } static class Sub extends Main { public synchronized void operationSub(){ try { while(i > 0) { i--; System.out.println("Sub print i = " + i); Thread.sleep(100); this.operationSup(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
当涉及到父类与子类相互执行的时候 可使用锁重入
异常释放锁
private int i = 0; public synchronized void operation(){ while(true){ try { i++; Thread.sleep(100); System.out.println(Thread.currentThread().getName() + " , i = " + i); if(i == 20){ //Integer.parseInt("a"); throw new RuntimeException(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
若是一个业务分为多个子模块去执行。彼此之间相互独立,若是其中一个业务出现异常,采起的方式是记录日志,其余业务不受影响继续执行
若是一个业务分为多个子模块去执行,彼此之间是关联的,若是其中一个业务出现异常,采起的方式是抛出RuntimeException,及时终止业务。
减少锁的粒度:synchronized关键字来优化代码块的执行时间
public void doLongTimeTask(){ try { System.out.println("当前线程开始:" + Thread.currentThread().getName() + ", 正在执行一个较长时间的业务操做,其内容不须要同步"); Thread.sleep(2000); synchronized(this){ System.out.println("当前线程:" + Thread.currentThread().getName() + ", 执行同步代码块,对其同步变量进行操做"); Thread.sleep(1000); } System.out.println("当前线程结束:" + Thread.currentThread().getName() + ", 执行完毕"); } catch (InterruptedException e) { e.printStackTrace(); } }
对任意的Object对象加锁
public void method1(){ synchronized (this) { //对象锁 try { System.out.println("do method1.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void method2(){ //类锁 synchronized (ObjectLock.class) { try { System.out.println("do method2.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private Object lock = new Object(); public void method3(){ //任何对象锁 synchronized (lock) { try { System.out.println("do method3.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
对字符串常量加锁 产生死循环
public void method() { //new String("字符串常量") synchronized ("字符串常量") { try { while(true){ System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始"); Thread.sleep(1000); System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
锁对象改变 若是锁所对象自己不发生改变,即便是属性改变,那么依然是同步的。 同一对象属性的修改不会影响锁的状况
public synchronized void changeAttributte(String name, int age) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始"); this.setName(name); this.setAge(age); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: " + this.getName() + ", " + this.getAge()); Thread.sleep(2000); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束"); } catch (InterruptedException e) { e.printStackTrace(); } }
死锁问题:在设计程序时就应该避免双方相互持有对方的锁的状况
public void run() { if(tag.equals("a")){ synchronized (lock1) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); } } } if(tag.equals("b")){ synchronized (lock2) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); } } } }