1.1 基础
一、概念
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
二、synchronized
可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。
三、示例
【com.xxy.thread01】My Thread

1 package com.xxy.thread01; 2 3 public class MyThread extends Thread{ 4 private int count = 5; 5 6 public synchronized void run() { 7 count--; 8 System.out.println(this.currentThread().getName() + " count=" + count); 9 } 10 11 public static void main(String[] args) { 12 /* 13 * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排队是按照CPU分配的先后顺序而定的) 14 * 一个线程想要执行synchronized修饰的方法里的代码: 15 * 1. 尝试获得锁 16 * 2. 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程会不断的尝试获得这把锁,直到拿到为止。 17 * 而且是多个线程同时去竞争这把锁(这就是会有锁竞争的问题)。 18 */ 19 MyThread myThread = new MyThread(); 20 Thread t1 = new Thread(myThread, "t1"); 21 Thread t2 = new Thread(myThread, "t2"); 22 Thread t3 = new Thread(myThread, "t3"); 23 Thread t4 = new Thread(myThread, "t4"); 24 Thread t5 = new Thread(myThread, "t5"); 25 t1.start(); 26 t2.start(); 27 t3.start(); 28 t4.start(); 29 t5.start(); 30 } 31 }
四、示例总结
当多个线程访问My Thread的run方法时,以排队的方式进行处理(这里排队是按照CPU分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法里的代码,首先是尝试获得锁,如果拿到锁,执行synchronized代码体内容:拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)。
1.2 多个线程多个锁
一、概念
多个线程多个锁:多个线程,每个线程都可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容。
二、示例:【com.xxy.sync002】MultiThread

1 package com.xxy.thread01; 2 3 public class MultiThread { 4 /*static*/ 5 private int number = 0; 6 /*static*/ 7 public synchronized void print(String tag){ 8 if(tag.equals("a")) { 9 number = 100; 10 System.out.println("tag a set over"); 11 try { 12 Thread.sleep(1000); 13 } catch (InterruptedException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 } else { 18 number = 200; 19 System.out.println("tab b set over"); 20 } 21 System.out.println("tag "+ tag +"number = " + number); 22 } 23 24 public static void main(String[] args) { 25 final MultiThread m1 = new MultiThread(); 26 final MultiThread m2 = new MultiThread(); 27 28 Thread t1 = new Thread(new Runnable() { 29 30 @Override 31 public void run() { 32 m1.print("a"); 33 } 34 }); 35 36 Thread t2 = new Thread(new Runnable() { 37 38 @Override 39 public void run() { 40 m2.print("b"); 41 } 42 }); 43 44 t1.start(); 45 t2.start(); 46 } 47 }
三、示例总结
关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当作锁,所以示例代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),两个对象,线程获得的就是两个不同的锁,他们互不影响。有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class)
1.3 对象锁的同步和异步
一、概念
同步:synchronized
同步的概念就是共享,我们要牢牢记住“共享”这两个字,如果不是共享的资源,就没有必要进行同步。
异步:asynchronized
异步的概念就是独立,相互之间不受任何制约。就好像我们学习http的时候,在页面发起的Ajax请求,我们还可以继续浏览或操作页面的内容,两者之间没有任何关系。
同步的目的就是为了线程安全,其实对于线程来说,需要满足两个特性:原子性(同步)、可见性。
二、示例【com.xxy.sync003】MyObject

1 package com.xxy.thread01; 2 3 public class MyObject { 4 public synchronized void method1() { 5 try { 6 System.out.println(Thread.currentThread().getName()); 7 Thread.sleep(4000); 8 } catch (InterruptedException e) { 9 // TODO Auto-generated catch block 10 e.printStackTrace(); 11 } 12 } 13 14 //synchronized 15 public void method2() { 16 System.out.println(Thread.currentThread().getName()); 17 } 18 19 public static void main(String[] args) { 20 final MyObject mo = new MyObject(); 21 /** 22 * 分析: 23 * t1线程先持有MyObject对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法。 24 * t1线程先持有MyObject对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。 25 */ 26 Thread t1 = new Thread(new Runnable() { 27 28 @Override 29 public void run() { 30 mo.method1(); 31 } 32 }, "t1"); 33 34 Thread t2 = new Thread(new Runnable() { 35 36 @Override 37 public void run() { 38 mo.method2(); 39 } 40 }, "t2"); 41 42 t1.start(); 43 t2.start(); 44 } 45 }
三、示例总结:
A线程先持有Object对象的Lock锁,B线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。
A线程现持有Object对象的Lock锁,B线程可以以异步的方式调用对象中的非synchronized修饰的方法。