【Java之并发】ReentrantLock和synchronized区别

1、ReentrantLock和synchronized区别:

相同:ReentrantLock提供了synchronized类似的功能和内存语义。

 不同:

1.ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。

2.ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。

3.ReentrantLock 的性能比synchronized会好点。

4.ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。

5、Lock的某些方法可以决定多长时间内尝试获取锁,如果获取不到就抛异常,这样就可以一定程度上减轻死锁的可能性。

如果锁被另一个线程占据了,synchronized只会一直等待,很容易错序死锁 

6、synchronized的话,锁的范围是整个方法或synchronized块部分;而Lock因为是方法调用,可以跨方法,灵活性更大 

7、便于测试,单元测试时,可以模拟Lock,确定是否获得了锁,而synchronized就没办法了


2、ReentrantLock比synchronized 强大在哪儿?

简单说: 

1、ReentrantLock可以实现fair lock 

 

public ReentrantLock(boolean fair) {   

    sync = (fair)? new FairSync() : new NonfairSync();  

}  

所谓fair lock就是看获得锁的顺序是不是和申请锁的时间的顺序是一致的 

 

2、ReentrantLock支持中断处理 

 

public final void acquireInterruptibly(int arg) throws InterruptedException {  

    if (Thread.interrupted())  

        throw new InterruptedException();  

    if (!tryAcquire(arg))  

        doAcquireInterruptibly(arg);  

}  

就是说那些持有锁的线程一直不释放,正在等待的线程可以放弃等待。 

 

3、ReentrantLock可以和condition结合使用 

 

public boolean hasWaiters(Condition condition) {  

    if (condition == null)  

        throw new NullPointerException();  

    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))  

        throw new IllegalArgumentException("not owner");  

    return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);  

}  

 

public int getWaitQueueLength(Condition condition) {  

    if (condition == null)  

        throw new NullPointerException();  

    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))  

        throw new IllegalArgumentException("not owner");  

    return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);  

}  

 

内置锁synchronized

显式锁Lock


3、处处都好?

看起来 ReentrantLock 无论在哪方面都比 synchronized 好 —— 所有 synchronized 能做的,它都能做,它拥有与synchronized 相同的内存和并发性语义,还拥有 synchronized 所没有的特性,在负荷下还拥有更好的性能。那么,我们是不是应当忘记 synchronized ,不再把它当作已经已经得到优化的好主意呢?或者甚至用 ReentrantLock 重写我们现有的synchronized 代码?实际上,几本 Java 编程方面介绍性的书籍在它们多线程的章节中就采用了这种方法,完全用 Lock 来做示例,只把 synchronized 当作历史。但我觉得这是把好事做得太过了。

4、还不要抛弃 synchronized

虽然 ReentrantLock 是个非常动人的实现,相对 synchronized 来说,它有一些重要的优势,但是我认为急于把 synchronized 视若敝屣,绝对是个严重的错误。 java.util.concurrent.lock 中的锁定类是用于高级用户和高级情况的工具。一般来说,除非您对 Lock 的某个高级特性有明确的需要,或者有明确的证据(而不是仅仅是怀疑)表明在特定情况下,同步已经成为可伸缩性的瓶颈,否则还是应当继续使用 synchronized。

为什么我在一个显然“更好的”实现的使用上主张保守呢?因为对于 java.util.concurrent.lock 中的锁定类来说,synchronized 仍然有一些优势。比如,在使用 synchronized 的时候,不能忘记释放锁;在退出 synchronized 块时,JVM 会为您做这件事。您很容易忘记用 finally 块释放锁,这对程序非常有害。您的程序能够通过测试,但会在实际工作中出现死锁,那时会很难指出原因(这也是为什么根本不让初级开发人员使用 Lock 的一个好理由。)

另一个原因是因为,当 JVM 用 synchronized 管理锁定请求和释放时,JVM 在生成线程转储时能够包括锁定信息。这些对调试非常有价值,因为它们能标识死锁或者其他异常行为的来源。 Lock 类只是普通的类,JVM 不知道具体哪个线程拥有 Lock 对象。而且,几乎每个开发人员都熟悉 synchronized,它可以在 JVM 的所有版本中工作。在 JDK 5.0 成为标准(从现在开始可能需要两年)之前,使用 Lock 类将意味着要利用的特性不是每个 JVM 都有的,而且不是每个开发人员都熟悉的。

5、什么时候选择用 ReentrantLock 代替 synchronized

既然如此,我们什么时候才应该使用 ReentrantLock 呢?答案非常简单 —— 在确实需要一些 synchronized 所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。 ReentrantLock 还具有可伸缩性的好处,应当在高度争用的情况下使用它,但是请记住,大多数 synchronized 块几乎从来没有出现过争用,所以可以把高度争用放在一边。我建议用 synchronized 开发,直到确实证明 synchronized 不合适,而不要仅仅是假设如果使用 ReentrantLock “性能会更好”。请记住,这些是供高级用户使用的高级工具。(而且,真正的高级用户喜欢选择能够找到的最简单工具,直到他们认为简单的工具不适用为止。)。一如既往,首先要把事情做好,然后再考虑是不是有必要做得更快。


Lock 框架是同步的兼容替代品,它提供了 synchronized 没有提供的许多特性,它的实现在争用下提供了更好的性能。但是,这些明显存在的好处,还不足以成为用 ReentrantLock 代替 synchronized 的理由。相反,应当根据您是否 需要ReentrantLock 的能力来作出选择。大多数情况下,您不应当选择它 —— synchronized 工作得很好,可以在所有 JVM 上工作,更多的开发人员了解它,而且不太容易出错。只有在真正需要 Lock 的时候才用它。在这些情况下,您会很高兴拥有这款工具。

6、详细对比:

首先,关于互斥锁:

所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别:

synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出现在同一个块结构中, 以及以更自由的顺序释放锁提供了可能. 

 

 

关于可重入: 

一、2.4.1 内部锁

Java 提供了原子性的内置锁机制: sychronized 块。它包含两个部分:锁对象的引用和这个锁保护的代码块:

synchronized(lock) {

// 访问或修改被锁保护的共享状态

}

内部锁扮演了互斥锁( mutual exclusion lock, 也称作 mutex )的角色,一个线程拥有锁的时候,别的线程阻塞等待。

 

2.4.2 重进入(Reentrancy )

重入性:指的是同一个线程多次试图获取它所占有的锁,请求会成功。当释放锁的时候,直到重入次数清零,锁才释放完毕。

Public class Widget {

      Public synchronized void doSomething(){

           …

      }

}

Public class LoggingWidget extends Widget {

   Public synchronized void doSomething(){

      System.out.println(toString()+”:calling doSomething”);

      Super.doSomething();

   }

}

 

二、一般来说,在多线程程序中,某个任务在持有某对象的锁后才能运行任务,其他任务只有在该任务释放同一对象锁后才能拥有对象锁,然后执行任务。于是,想到,同一个任务在持有同一个对象的锁后,在不释放锁的情况下,继续调用同一个对象的其他同步(synchronized)方法,该任务是否会再次持有该对象锁呢? 

    答案是肯定的。同一个任务在调用同一个对象上的其他synchronized方法,可以再次获得该对象锁。 

 

Java代码   收藏代码
  1. synchronized  m1(){  
  2. //加入此时对锁a的计数是N  
  3.  m2();  //进入m2的方法体之后锁计数是N+1,离开m2后是N  
  4. }  
  5. synchronized m2(){}  

 同一任务和对象锁的问题:http://www.iteye.com/topic/728485

 

 

 

Java代码   收藏代码
  1. /*public class ReentrantLock  
  2. extends Object implements Lock, Serializable 
  3. */  

  

一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

 

ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。

 

此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。

JDK:http://www.xasxt.com/java/api/java/util/concurrent/locks/ReentrantLock.html

 

 

Java代码   收藏代码
  1. /*构造方法摘要 
  2. ReentrantLock()  
  3.           创建一个 ReentrantLock 的实例。 
  4. ReentrantLock(boolean fair)  
  5.           创建一个具有给定公平策略的 ReentrantLock。 
  6. */  

  

Java代码   收藏代码
  1. /**public void lock() 
  2. 获取锁。 
  3. 如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。 
  4. 如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。 
  5. 如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。 
  6. */  

  

ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B 2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是 一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock 不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock 处理了这个中断,并且不再等待这个锁的到来,完全放弃。请看例子:

Example1:

 

Java代码   收藏代码
  1. package test;  
  2.   
  3. public interface IBuffer {  
  4.     public void write();  
  5.     public void read() throws InterruptedException;  
  6. }  

使用Synchronized:

Java代码   收藏代码
  1. package test;  
  2.   
  3. public class Buffer implements IBuffer {  
  4.   
  5.     private Object lock;  
  6.   
  7.     public Buffer() {  
  8.         lock = this;  
  9.     }  
  10.   
  11.     public void write() {  
  12.         synchronized (lock) {  
  13.             long startTime = System.currentTimeMillis();  
  14.             System.out.println("开始往这个buff写入数据…");  
  15.             for (;;)// 模拟要处理很长时间  
  16.             {  
  17.                 if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)  
  18.                     break;  
  19.             }  
  20.             System.out.println("终于写完了");  
  21.         }  
  22.     }  
  23.   
  24.     public void read() {  
  25.         synchronized (lock) {  
  26.             System.out.println("从这个buff读数据");  
  27.         }  
  28.     }  
  29.   
  30. }  

   使用ReentrantLock:

Java代码   收藏代码
  1. package test;  
  2. import java.util.concurrent.locks.ReentrantLock;  
  3. public class BufferInterruptibly implements IBuffer {  
  4.   
  5.     private ReentrantLock lock = new ReentrantLock();  
  6.   
  7.     public void write() {  
  8.         lock.lock();  
  9.         try {  
  10.             long startTime = System.currentTimeMillis();  
  11.             System.out.println("开始往这个buff写入数据…");  
  12.             for (;;)// 模拟要处理很长时间  
  13.             {  
  14.                 if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)  
  15.                     break;  
  16.             }  
  17.             System.out.println("终于写完了");  
  18.         } finally {  
  19.             lock.unlock();  
  20.         }  
  21.     }  
  22.   
  23.     public void read() throws InterruptedException{  
  24.         lock.lockInterruptibly();// 注意这里,可以响应中断  
  25.         try {  
  26.             System.out.println("从这个buff读数据");  
  27.         } finally {  
  28.             lock.unlock();  
  29.         }  
  30.     }  
  31.   
  32. }  

  

测试类(注意那两个线程不是内部类!):

Java代码   收藏代码
  1. package test;  
  2.   
  3. public class Test {  
  4.      //是用ReentrantLock,还是用synchronized  
  5.     public static boolean useSynchronized = false;  
  6.     public static void main(String[] args) {  
  7.         IBuffer buff = null;  
  8.         if(useSynchronized){  
  9.             buff = new Buffer();  
  10.         }else{  
  11.             buff = new BufferInterruptibly();      
  12.         }  
  13.         final Writer writer = new Writer(buff);  
  14.         final Reader reader = new Reader(buff);  
  15.         writer.start();  
  16.         reader.start();  
  17.         new Thread(new Runnable() {  
  18.             public void run() {  
  19.                 long start = System.currentTimeMillis();  
  20.                 for (;;) {  
  21.                     // 等5秒钟去中断读  
  22.                     if (System.currentTimeMillis() - start > 5000) {  
  23.                         System.out.println("不等了,尝试中断");  
  24.                         reader.interrupt();  
  25.                         break;  
  26.                     }  
  27.   
  28.                 }  
  29.   
  30.             }  
  31.         }).start();  
  32.     }      
  33. }  
  34.   
  35.     class Writer extends Thread {     
  36.         private IBuffer buff;  
  37.       
  38.         public Writer(IBuffer buff) {  
  39.             this.buff = buff;  
  40.         }  
  41.       
  42.         @Override  
  43.         public void run() {  
  44.             buff.write();  
  45.         }  
  46.     }  
  47.       
  48.     class Reader extends Thread {  
  49.         private IBuffer buff;  
  50.         public Reader(IBuffer buff) {  
  51.             this.buff = buff;  
  52.         }  
  53.         @Override  
  54.         public void run() {  
  55.             try {  
  56.                 buff.read();  
  57.             } catch (InterruptedException e) {  
  58.                 System.out.println("我不读了");     
  59.             }  
  60.             System.out.println("读结束");  
  61.         }  
  62.     }  

 结果:

使用ReentrantLock时:

开始往这个buff写入数据…

不等了,尝试中断

我不读了

读结束

 

使用Synchronized时:

开始往这个buff写入数据…

不等了,尝试中断

实例来源:http://blog.csdn.net/quqi99/article/details/5298017

 

 

实例2:

http://junlas.iteye.com/blog/846460

实例3:

http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html

 

 

重要:

一个证明可中断的例子:http://yanxuxin.iteye.com/blog/566713

关于多线程问题,signalAll,await问题:http://www.iteye.com/problems/72378

ReentrantLock :http://hujin.iteye.com/blog/479689

 

java的concurrent用法详解:

http://www.open-open.com/bbs/view/1320131360999

 

ReentrantLock-互斥同步器:

http://www.cnblogs.com/mandela/archive/2011/04/08/2009810.html

 

一个重要Example:

 

Java代码   收藏代码
  1. package tags;  
  2.   
  3. import java.util.Calendar;  
  4.   
  5. public class TestLock {  
  6.     private ReentrantLock lock = null;  
  7.       
  8.     public int data = 100;     // 用于线程同步访问的共享数据  
  9.   
  10.     public TestLock() {  
  11.         lock = new ReentrantLock(); // 创建一个自由竞争的可重入锁  
  12.     }  
  13.     public ReentrantLock getLock() {  
  14.         return lock;  
  15.     }  
  16.       
  17.     public void testReentry() {  
  18.         lock.lock();  
  19.         Calendar now = Calendar.getInstance();  
  20.         System.out.println(now.getTime() + " " + Thread.currentThread() + " get lock.");  
  21.     }  
  22.   
  23.     public static void main(String[] args) {  
  24.         TestLock tester = new TestLock();  
  25.   
  26.         //1、测试可重入  
  27.         tester.testReentry();  
  28.         tester.testReentry(); // 能执行到这里而不阻塞,表示锁可重入  
  29.         tester.testReentry(); // 再次重入  
  30.   
  31.         // 释放重入测试的锁,要按重入的数量解锁,否则其他线程无法获取该锁。  
  32.         tester.getLock().unlock();  
  33.         tester.getLock().unlock();  
  34.         tester.getLock().unlock();  
  35.   
  36.         //2、测试互斥  
  37.         // 启动3个线程测试在锁保护下的共享数据data的访问  
  38.         new Thread(new workerThread(tester)).start();  
  39.         new Thread(new workerThread(tester)).start();  
  40.         new Thread(new workerThread(tester)).start();  
  41.     }  
  42.   
  43.   
  44.     // 线程调用的方法  
  45.     public void testRun() throws Exception {  
  46.         lock.lock();  
  47.   
  48.         Calendar now = Calendar.getInstance();  
  49.         try {  
  50.             // 获取锁后显示 当前时间 当前调用线程 共享数据的值(并使共享数据 + 1)  
  51.             System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++);  
  52.             Thread.sleep(1000);  
  53.         } catch (Exception e) {  
  54.             e.printStackTrace();  
  55.         } finally {  
  56.             lock.unlock();  
  57.         }  
  58.     }  
  59. }  
  60.   
  61. // 工作线程,调用TestServer.testRun  
  62. class workerThread implements Runnable {  
  63.   
  64.     private TestLock tester = null;  
  65.   
  66.     public workerThread(TestLock testLock) {  
  67.         this.tester = testLock;  
  68.     }  
  69.   
  70.     public void run() {  
  71.         try {  
  72.             tester.testRun();  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         }  
  76.     }  
  77. }  

Example3:

 

Java代码   收藏代码
  1. package tags;  
  2. import java.util.concurrent.locks.ReentrantLock;  
  3.   
  4. public class ReentrantLockSample {  
  5.   
  6.     public static void main(String[] args) {  
  7.         testSynchronized();  
  8.         //testReentrantLock();  
  9.     }  
  10.   
  11.     public static void testReentrantLock() {  
  12.         final SampleSupport1 support = new SampleSupport1();  
  13.         Thread first = new Thread(new Runnable() {  
  14.             public void run() {  
  15.                 try {  
  16.                     support.doSomething();  
  17.                 }  
  18.                 catch (InterruptedException e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         });  
  23.   
  24.         Thread second = new Thread(new Runnable() {  
  25.             public void run() {  
  26.                 try {  
  27.                     support.doSomething();  
  28.                 }  
  29.                 catch (InterruptedException e) {  
  30.                     System.out.println("Second Thread Interrupted without executing counter++,beacuse it waits a long time.");  
  31.                 }  
  32.             }  
  33.         });  
  34.   
  35.         executeTest(first, second);  
  36.     }  
  37.   
  38.     public static void testSynchronized() {  
  39.         final SampleSupport2 support2 = new SampleSupport2();  
  40.   
  41.         Runnable runnable = new Runnable() {  
  42.             public void run() {  
  43.                 support2.doSomething();  
  44.             }  
  45.         };  
  46.   
  47.         Thread third = new Thread(runnable);  
  48.         Thread fourth = new Thread(runnable);  
  49.   
  50.         executeTest(third, fourth);  
  51.     }  
  52.   
  53.     /** 
  54.      * Make thread a run faster than thread b, 
  55.      * then thread b will be interruted after about 1s. 
  56.      * @param a 
  57.      * @param b 
  58.      */  
  59.     public static void executeTest(Thread a, Thread b) {  
  60.         a.start();  
  61.         try {  
  62.             Thread.sleep(100);  
  63.             b.start(); // The main thread sleep 100ms, and then start the second thread.  
  64.   
  65.             Thread.sleep(1000);  
  66.     // 1s later, the main thread decided not to allow the second thread wait any longer.  
  67.             b.interrupt();   
  68.         }  
  69.         catch (InterruptedException e) {  
  70.             e.printStackTrace();  
  71.         }  
  72.     }  
  73. }  
  74.   
  75. abstract class SampleSupport {  
  76.   
  77.     protected int counter;  
  78.   
  79.     /** 
  80.      * A simple countdown,it will stop after about 5s.  
  81.      */  
  82.     public void startTheCountdown() {  
  83.         long currentTime = System.currentTimeMillis();  
  84.         for (;;) {  
  85.             long diff = System.currentTimeMillis() - currentTime;  
  86.             if (diff > 5000) {  
  87.                 break;  
  88.             }  
  89.         }  
  90.     }  
  91. }  
  92.   
  93. class SampleSupport1 extends SampleSupport {  
  94.   
  95.     private final ReentrantLock lock = new ReentrantLock();  
  96.   
  97.     public void doSomething() throws InterruptedException {  
  98.         lock.lockInterruptibly(); // (1)  
  99.         System.out.println(Thread.currentThread().getName() + " will execute counter++.");  
  100.         startTheCountdown();  
  101.         try {  
  102.             counter++;  
  103.         }  
  104.         finally {  
  105.             lock.unlock();  
  106.         }  
  107.     }  
  108. }  
  109.   
  110. class SampleSupport2 extends SampleSupport {  
  111.   
  112.     public synchronized void doSomething() {  
  113.         System.out.println(Thread.currentThread().getName() + " will execute counter++.");  
  114.         startTheCountdown();  
  115.         counter++;  
  116.     }  
  117. }  

 在这个例子中,辅助类SampleSupport提供一个倒计时的功能startTheCountdown(),这里倒计时5s左右。SampleSupport1,SampleSupport2继承其并分别的具有doSomething()方法,任何进入方法的线程会运行5s左右之后counter++然后离开方法释放锁。SampleSupport1是使用ReentrantLock机制,SampleSupport2是使用synchronized机制。 


    testSynchronized()和testReentrantLock()都分别开启两个线程执行测试方法executeTest(),这个方法会让一个线程先启动,另一个过100ms左右启动,并且隔1s左右试图中断后者。结果正如之前提到的第二点:interrupt()对于synchronized是没有作用的,它依然会等待5s左右获得锁执行counter++;而ReentrantLock机制可以保证在线程还未获得并且试图获得锁时如果发现线程中断,则抛出异常清除中断标记退出竞争。所以testReentrantLock()中second线程不会继续去竞争锁,执行异常内的打印语句后线程运行结束。 

来源:http://yanxuxin.iteye.com/blog/566713

 

Example4:

三个线程,线程名分别为A、B、C,设计程序使得三个线程循环打印“ABC”10次后终止。如:ABCABCABCABCABCABCABCABCABCABC

 

Java代码   收藏代码
  1. package tags;  
  2.   
  3. import java.util.concurrent.locks.ReentrantLock;  
  4.   
  5. public class ReentrantLockPractice {  
  6.   
  7.     static ReentrantLock lock = new ReentrantLock();  
  8.     private static String[] threadArr = {"A","B","C"};  
  9.       
  10.     public static void main(String[] args){  
  11.         ReentrantLockPractice pc = new ReentrantLockPractice();  
  12.         pc.startDemo();  
  13.     }  
  14.       
  15.     void startDemo(){  
  16.         for(int i = 0;i<10;i++){  
  17.             for(String name : threadArr){  
  18.                 TestThread t = new TestThread(name);  
  19.                 t.start();  
  20.                 try {  
  21.                     Thread.sleep(100);  
  22.                 } catch (InterruptedException e) {  
  23.                     e.printStackTrace();  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28.       
  29.   
  30.     class TestThread extends Thread{  
  31.           
  32.         //自定义线程名字  
  33.         TestThread(String str){  
  34.             super(str);           
  35.         }  
  36.           
  37.         public void run(){  
  38.             try {  
  39.                 lock.lockInterruptibly();  
  40.                 System.out.print(Thread.currentThread().getName());  
  41.             } catch (InterruptedException e) {  
  42.                 e.printStackTrace();  
  43.             } finally{  
  44.                 lock.unlock();  
  45.             }     
  46.         }  
  47.     }  
  48.       
  49. }  

 注意与Example2的区别,一个线材类定义在内部,一个在外部,注意区别。

 其他方法:

http://hxraid.iteye.com/blog/607228

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值