public class LockTest { public static void main(String[] args){ final Outputer outputer = new Outputer(); new Thread(new Runnable(){ @Override public void run() { while(true){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } outputer.output("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }).start(); new Thread(new Runnable(){ @Override public void run() { while(true){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } outputer.output("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); }//a的数量与b的数量一致 } }).start(); } static class Outputer{ public void output(String name){ int len = name.length(); try{ for(int i=0;i<len;i++){ System.out.print(name.charAt(i)); } System.out.println(); }finally{ } } } }
static class Outputer{ public synchronized void output(String name){ int len = name.length(); //..... } }这样一来,我们就保证了Outputer类里的output方法是原子性的,不会有两个线程同时执行它。
static class Outputer{ Lock lock = new ReentrantLock(); public void output(String name){ int len = name.length(); lock.lock(); //标识1 try{ for(int i=0;i<len;i++){ System.out.print(name.charAt(i)); } System.out.println(); }finally{ lock.unlock(); //标识2 } }线程a执行到上面代码的标识1处加锁,当线程a在输出字符a时,线程b也执行到了标识1处。此时线程b是不能获得锁的。它被阻塞到标识1处,直到线程a打印完之后在标识2处释放了锁。(线程a线程b共用一把锁,也就是Lock lock = new ReentrantLock())
上面的问题中output的主体(len是方法内部的局部变量,为每个线程自有,互不干涉)被全部互斥,它保证了任何时候,都只有一个线程执行标识1与标识2直接的代码。
但是我们得意识到:对共有数据的操作,基本可以分为两类,读与写。public class ReadWriteLockTest { public static void main(String[] args) { final Queue3 q3 = new Queue3(); for(int i=0;i<3;i++) { new Thread(){ public void run(){ while(true){ q3.get(); } } }.start(); new Thread(){ public void run(){ while(true){ q3.put(new Random().nextInt(10000)); } } }.start(); } } } class Queue3{ private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。 public void get(){ try { System.out.println(Thread.currentThread().getName() + " be ready to read data!"); Thread.sleep((long)(Math.random()*1000)); System.out.println(Thread.currentThread().getName() + "have read data :" + data); } catch (InterruptedException e) { e.printStackTrace(); } } public void put(Object data){ try { System.out.println(Thread.currentThread().getName() + " be ready to write data!"); Thread.sleep((long)(Math.random()*1000)); this.data = data; System.out.println(Thread.currentThread().getName() + " have write data: " + data); } catch (InterruptedException e) { e.printStackTrace(); } } }结果如下
public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable看看使用方法
class Queue3{ private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。 ReadWriteLock rwl = new ReentrantReadWriteLock(); public void get(){ rwl.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to read data!"); Thread.sleep(20); System.out.println(Thread.currentThread().getName() + " have read data :" + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.readLock().unlock(); } } public void put(Object data){ rwl.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to write data!"); Thread.sleep(20); this.data = data; System.out.println(Thread.currentThread().getName() + " have write data: " + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.writeLock().unlock(); } } }结果如下
而线程2 4 0的读是可以同步进行的。
这是读写锁最简单的例子,下一节,我们看一个稍微复杂的,把读锁与写锁放到一个方法内的例子。
感谢glt