Java 线程同步详解

时间:2021-05-20

Java 线程同步根本上是要符合一个逻辑:加锁------>修改------>释放锁

1、同步代码块

示例如下:

public class SyncBlock { static class DataWrap { int i; } static class SyncBlockThread extends Thread { private DataWrap date; public SyncBlockThread(DataWrap dataWrap) { this.date = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (date) { date.i++; try { sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + " " + date.i); } } } } public static void main(String[] args) { //多线程实现变量i依次加一输出 DataWrap dataWrap = new DataWrap(); new SyncBlockThread(dataWrap).start(); new SyncBlockThread(dataWrap).start(); new SyncBlockThread(dataWrap).start(); }}

示例中希望按照顺序依次输出整数。

通常同步代码块是需要锁定的对象,一般是需要并发访问的共享资源,任何线程在修改指定资源之前都首先对该资源加锁,在加锁期间其它线程无法修改该资源。从而保证了线程的安全性。另外线程在调用sleep或者yield时并不会让出资源锁。

2、同步方法

public class SyncMethod { static class DataWrap{ int i; public synchronized void valueGrow(){ i++; try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + i); } } static class SyncMethodThread extends Thread { DataWrap dataWrap; public SyncMethodThread(DataWrap dataWrap){ this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { dataWrap.valueGrow(); } } } public static void main(String[] args) { //实现顺序增长并输出Datawrap中的i DataWrap dataWrap = new DataWrap(); new SyncMethodThread(dataWrap).start(); new SyncMethodThread(dataWrap).start(); new SyncMethodThread(dataWrap).start(); }}

同步方法是使用synchronized关键字修饰的某个方法,同步方法锁定的就是该对象本身,所以当一个线程调用了某个对象的同步方法后,如有其它线程调用该对象的其它同步方法,也依然要等待释放该对象的锁,因为该对象已被锁定。

3、同步锁

通过定义同步锁对象实现同步,这种情况下,同步锁使用Lock对象充当。

import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class SyncLock { static class DataWrap{ Lock lock = new ReentrantLock(); int i; public void valueGrow(){ lock.lock(); try { i++; try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + i); } finally { lock.unlock(); } } } static class SyncLockThread extends Thread { DataWrap dataWrap; public SyncLockThread(DataWrap dataWrap){ this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { dataWrap.valueGrow(); } } } public static void main(String[] args) { //实现顺序增长并输出Datawrap中的i DataWrap dataWrap = new DataWrap(); new SyncLockThread(dataWrap).start(); new SyncLockThread(dataWrap).start(); new SyncLockThread(dataWrap).start(); }}

使用锁对象实现线程同步会更灵活一些,某些锁还具有一些特定的功能,其中比较常用的ReadWriteLock读写锁,ReentrantLock可重入锁。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章