你的位置:首页 > Java教程

[Java教程]Java 线程同步


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可重入锁。