一、synchronized
同步关键字,分为同步代码块和同步函数
二、对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用)
对象的创建是以类为模板的
1、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,同一时间只能执行一个,另一个必须要等待当前线程执行完才能执行(同一个对象:见下面的testSynchronized,分为两个线程,两个线程访问的是一个方法)(一个对象两个线程一个方法)
例子:
1 public class TestSynchronized { 2 public void test1(){ 3 synchronized(this) { 4 System.out.println("1"+this); 5 int i = 5; 6 while( i-- > 0) { 7 System.out.println(Thread.currentThread().getName() + " : " + i); 8 try { 9 Thread.sleep(500); 10 } catch (InterruptedException e) { 11 // TODO Auto-generated catch block 12 e.printStackTrace(); 13 } 14 } 15 } 16 } 17 public static void main(String[] args) { 18 final TestSynchronized testSynchronized = new TestSynchronized(); 19 final TestSynchronized testSynchronized1 = new TestSynchronized(); 20 Thread thread1 = new Thread(new Runnable() { 21 22 @Override 23 public void run() { 24 testSynchronized.test1(); 25 } 26 },"test1"); 27 Thread thread3 = new Thread(new Runnable() { 28 29 @Override 30 public void run() { 31 testSynchronized.test1(); 32 } 33 },"test3"); 34 35 thread1.start(); 36 thread3.start(); 37 } 38 }
结果:
2、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,两个交替进行,因为对象的创建是以类为模板的,所以两个对象都会有自己独立的方法(不同对象:testSynchronized和testSynchronized1,分为两个线程,两个线程访问的是一个方法)(两个对象两个线程一个方法)
例子:和第一个的例子相比仅仅修改了第31行
1 public class TestSynchronized { 2 public void test1(){ 3 synchronized(this) { 4 System.out.println("1"+this); 5 int i = 5; 6 while( i-- > 0) { 7 System.out.println(Thread.currentThread().getName() + " : " + i); 8 try { 9 Thread.sleep(500); 10 } catch (InterruptedException e) { 11 // TODO Auto-generated catch block 12 e.printStackTrace(); 13 } 14 } 15 } 16 } 17 public static void main(String[] args) { 18 final TestSynchronized testSynchronized = new TestSynchronized(); 19 final TestSynchronized testSynchronized1 = new TestSynchronized(); 20 Thread thread1 = new Thread(new Runnable() { 21 22 @Override 23 public void run() { 24 testSynchronized.test1(); 25 } 26 },"test1"); 27 Thread thread3 = new Thread(new Runnable() { 28 29 @Override 30 public void run() { 31 testSynchronized1.test1(); 32 } 33 },"test3"); 34 thread1.start(); 35 thread3.start(); 36 } 37 }
结果:
3、(两个线程同一对象)当一个线程已经访问了该类中的一个synchronized方法,另一个线程就不能再去访问访问其他的synchronized方法(对象锁是锁住了对象,所以只能执行完这个再去执行另一个)(一个对象两个线程两个方法)
例子:
1 public class TestSynchronized { 2 public void test1(){ 3 synchronized(this) { 4 System.out.println("1"+this); 5 int i = 5; 6 while( i-- > 0) { 7 System.out.println(Thread.currentThread().getName() + " : " + i); 8 try { 9 Thread.sleep(500); 10 } catch (InterruptedException e) { 11 // TODO Auto-generated catch block 12 e.printStackTrace(); 13 } 14 } 15 } 16 } 17 public synchronized void test2(){ 18 System.out.println(this); 19 int i = 5; 20 while( i-- > 0) { 21 System.out.println(Thread.currentThread().getName() + " : " + i); 22 try { 23 Thread.sleep(500); 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } 27 } 28 } 29 public static void main(String[] args) { 30 final TestSynchronized testSynchronized = new TestSynchronized(); 31 final TestSynchronized testSynchronized1 = new TestSynchronized(); 32 Thread thread1 = new Thread(new Runnable() { 33 34 @Override 35 public void run() { 36 testSynchronized.test1(); 37 } 38 },"test1"); 39 Thread thread2 = new Thread(new Runnable() { 40 41 @Override 42 public void run() { 43 testSynchronized.test2(); 44 } 45 },"test2"); 46 thread1.start(); 47 thread2.start(); 48 } 49 }
结果:
4、(同一个对象)当一个线程已经访问了一个类的synchronized方法,那么另一个线程也可以访问其他的非synchronized方法,结果是交替进行的(一个对象两个线程两个方法[一个synchronized一个非synchronized的])
进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)
例子:
1 public class TestSynchronized { 2 public void test1(){ 3 synchronized(this) { 4 System.out.println("1"+this); 5 int i = 5; 6 while( i-- > 0) { 7 System.out.println(Thread.currentThread().getName() + " : " + i); 8 try { 9 Thread.sleep(500); 10 } catch (InterruptedException e) { 11 // TODO Auto-generated catch block 12 e.printStackTrace(); 13 } 14 } 15 } 16 } 17 //非synchronized 18 public void test2(){ 19 System.out.println(this); 20 int i = 5; 21 while( i-- > 0) { 22 System.out.println(Thread.currentThread().getName() + " : " + i); 23 try { 24 Thread.sleep(500); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 } 29 } 30 public static void main(String[] args) { 31 final TestSynchronized testSynchronized = new TestSynchronized(); 32 final TestSynchronized testSynchronized1 = new TestSynchronized(); 33 Thread thread1 = new Thread(new Runnable() { 34 35 @Override 36 public void run() { 37 testSynchronized.test1(); 38 } 39 },"test1"); 40 Thread thread2 = new Thread(new Runnable() { 41 42 @Override 43 public void run() { 44 testSynchronized.test2(); 45 } 46 },"test2"); 47 48 thread2.start(); 49 thread1.start(); 50 } 51 }
结果:
三、加了static后现成的执行
1、对于一个类,一个线程访问了加了static的synchronized方法,另一个线程同样可以访问未加static的synchronized方法,所以结果是交替进行,因为类和对象不同(static修饰后锁住的是类,所有对象共享,而没有加static锁住的是对象,只有每个对象私有)(一个对象一个类两个线程两个方法)
例子:
1 public class TestSynchronized { 2 public void test1(){ 3 synchronized(this) { 4 int i = 5; 5 while( i-- > 0) { 6 System.out.println(Thread.currentThread().getName() + " : " + i); 7 try { 8 Thread.sleep(500); 9 } catch (InterruptedException e) { 10 // TODO Auto-generated catch block 11 e.printStackTrace(); 12 } 13 } 14 } 15 } 16 public static synchronized void test2(){ 17 int i = 5; 18 while( i-- > 0) { 19 System.out.println(Thread.currentThread().getName() + " : " + i); 20 try { 21 Thread.sleep(500); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 } 27 public static void main(String[] args) { 28 final TestSynchronized testSynchronized = new TestSynchronized(); 29 Thread thread1 = new Thread(new Runnable() { 30 31 @Override 32 public void run() {
//对象调用的是该对象自己的方法 33 testSynchronized.test1(); 34 } 35 },"test1"); 36 Thread thread2 = new Thread(new Runnable() { 37 38 @Override 39 public void run() {
//类调用的是类方法 40 TestSynchronized.test2(); 41 } 42 },"test2"); 43 thread2.start(); 44 thread1.start(); 45 } 46 }
结果:
2、两个都是被static修饰的synchronized方法,结果是一个线程等待另一个线程执行完才会执行,因为类是一样的(和同一个对象的理解差不多),方法被synchronized修饰只能一个执行完再执行另一个(一个类两个线程两个方法)
例子:
1 public class TestSynchronized { 2 public static void test1(){ 3 synchronized(TestSynchronized.class) { 4 int i = 5; 5 while( i-- > 0) { 6 System.out.println(Thread.currentThread().getName() + " : " + i); 7 try { 8 Thread.sleep(500); 9 } catch (InterruptedException e) { 10 // TODO Auto-generated catch block 11 e.printStackTrace(); 12 } 13 } 14 } 15 } 16 public static synchronized void test2(){ 17 int i = 5; 18 while( i-- > 0) { 19 System.out.println(Thread.currentThread().getName() + " : " + i); 20 try { 21 Thread.sleep(500); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 } 27 public static void main(String[] args) { 28 final TestSynchronized testSynchronized = new TestSynchronized(); 29 Thread thread1 = new Thread(new Runnable() { 30 31 @Override 32 public void run() { 33 TestSynchronized.test1(); 34 } 35 },"test1"); 36 Thread thread2 = new Thread(new Runnable() { 37 38 @Override 39 public void run() { 40 TestSynchronized.test2(); 41 } 42 },"test2"); 43 44 thread2.start(); 45 thread1.start(); 46 } 47 }
结果:
补充:
面试的一道题:
一个只被synchronized修饰的方法fun(),现有两个对象a,b,分别是两个线程t1,t2
①a.fun()和b.fun()可以同时进行吗?
答:可以,因为是两个为不同的对象,对象的创建是以类为模板的,所以这两个对象中都会有自己的fun()方法,所以两个线程开启后会交替进行,如上面的二2
②回答完可以后,怎么可以让两个分开进行即一个完了之后再进行另一个?
答:给方法加上static关键字,static锁住了类,此时锁为“类锁”,所以虽然对象不一样但是类都是一样的,所以简单说就是一个类两个线程调用一个方法,肯定是一个执行完再执行另一个