Java 线程同步详解
Java线程同步根本上是要符合一个逻辑:加锁------>修改------>释放锁
1、同步代码块
示例如下:
publicclassSyncBlock{ staticclassDataWrap{ inti; } staticclassSyncBlockThreadextendsThread{ privateDataWrapdate; publicSyncBlockThread(DataWrapdataWrap){ this.date=dataWrap; } @Override publicvoidrun(){ for(inti=0;i<10;i++){ synchronized(date){ date.i++; try{ sleep(1); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println(getName()+""+date.i); } } } } publicstaticvoidmain(String[]args){ //多线程实现变量i依次加一输出 DataWrapdataWrap=newDataWrap(); newSyncBlockThread(dataWrap).start(); newSyncBlockThread(dataWrap).start(); newSyncBlockThread(dataWrap).start(); } }
示例中希望按照顺序依次输出整数。
通常同步代码块是需要锁定的对象,一般是需要并发访问的共享资源,任何线程在修改指定资源之前都首先对该资源加锁,在加锁期间其它线程无法修改该资源。从而保证了线程的安全性。另外线程在调用sleep或者yield时并不会让出资源锁。
2、同步方法
publicclassSyncMethod{ staticclassDataWrap{ inti; publicsynchronizedvoidvalueGrow(){ i++; try{ Thread.sleep(1); }catch(InterruptedExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+""+i); } } staticclassSyncMethodThreadextendsThread{ DataWrapdataWrap; publicSyncMethodThread(DataWrapdataWrap){ this.dataWrap=dataWrap; } @Override publicvoidrun(){ for(inti=0;i<10;i++){ dataWrap.valueGrow(); } } } publicstaticvoidmain(String[]args){ //实现顺序增长并输出Datawrap中的i DataWrapdataWrap=newDataWrap(); newSyncMethodThread(dataWrap).start(); newSyncMethodThread(dataWrap).start(); newSyncMethodThread(dataWrap).start(); } }
同步方法是使用synchronized关键字修饰的某个方法,同步方法锁定的就是该对象本身,所以当一个线程调用了某个对象的同步方法后,如有其它线程调用该对象的其它同步方法,也依然要等待释放该对象的锁,因为该对象已被锁定。
3、同步锁
通过定义同步锁对象实现同步,这种情况下,同步锁使用Lock对象充当。
importjava.util.concurrent.locks.Lock; importjava.util.concurrent.locks.ReentrantLock; publicclassSyncLock{ staticclassDataWrap{ Locklock=newReentrantLock(); inti; publicvoidvalueGrow(){ lock.lock(); try{ i++; try{ Thread.sleep(1); }catch(InterruptedExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+""+i); }finally{ lock.unlock(); } } } staticclassSyncLockThreadextendsThread{ DataWrapdataWrap; publicSyncLockThread(DataWrapdataWrap){ this.dataWrap=dataWrap; } @Override publicvoidrun(){ for(inti=0;i<10;i++){ dataWrap.valueGrow(); } } } publicstaticvoidmain(String[]args){ //实现顺序增长并输出Datawrap中的i DataWrapdataWrap=newDataWrap(); newSyncLockThread(dataWrap).start(); newSyncLockThread(dataWrap).start(); newSyncLockThread(dataWrap).start(); } }
使用锁对象实现线程同步会更灵活一些,某些锁还具有一些特定的功能,其中比较常用的ReadWriteLock读写锁,ReentrantLock可重入锁。