什么是线程同步?
当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。
为什么要线程同步?
因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常
同步机制:
在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。
Java多线程支持方法同步,方法同步只需用用synchronized来修饰方法即可,那么这个方法就是同步方法了。
五种同步线程的方法
1.同步方法:使用sychronized关键字修饰方法,由于java的每个对象都有一个内置锁,当用此关键字修饰方法(静态与非静态都可修饰)时,内置锁会保护整个方法,在调用该方法时,在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
2.同步代码块:既有sychronized修饰的语句块,被该关键字修饰的语句块会被自动加上内置锁,从而实现同步。(注意:线程同步是一个高开销的操作,因此应当尽量减少同步的内容,通常没必要同步整个方法)
/*** 定义一个类,包含了线程类需要调用的方法 */ class Compute1{ //通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块 private Object object1 = new Object(); public void execute(){ synchronized(object1){ for(int i = 0; i<100; i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("compute1:execute1 " + i++); } } } public synchronized void execute2(){ synchronized(object1){ for(int i = 0; i<100; i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("compute1:execute2 " + i++); } } }}
如果想要使用synchronized同步代码块达到和使用synchronized方法同样的效果,可以锁定this引用:
synchronized(this){…}
3.使用特殊域变量(Volatile)实现线程同步.因为Volatile不能保证原子操作导致的,因此Volatile不能代替sychronized,此外Volatile会组织编译器对代码优化,因此不建议使用它,
4.使用重入锁对线同步(javaSE5.0以上中新增了一个java.util.concurrent包来支持同步)
5.使用局部变量实现线程同步