- 三个线程轮流打印ABC
- 三个线程轮流输出从1-100
- Java核心技术卷I上的内容
- 任务线程池的一个使用示例
package tacos.thread; import org.junit.Test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadDemo { public static String threadName = "A"; // 默认为A public static Lock lock = new ReentrantLock(); public static Condition conA = lock.newCondition(); public static Condition conB = lock.newCondition(); public static Condition conC = lock.newCondition(); @Test public void test() { ExecutorService es = Executors.newFixedThreadPool(3); // 线程开始执行的顺序和结果是无关的 es.execute(new ThreadB()); es.execute(new ThreadC()); es.execute(new ThreadA()); // es.execute(new ThreadB()); // es.execute(new ThreadC()); // 单独运行test()方法时,当前线程需要暂停一段时间才能保证每个任务都能顺利输出10次; // 如果把整个java项目启动运行起来,就不需要下面暂停当前线程这一步 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } es.shutdown(); } class ThreadA implements Runnable { @Override public void run() { for(int k=1; k<=10; k++) { lock.lock(); try { // 这里必须用while, 不断地尝试才行 while (!threadName.equals("A")) { try { // 在await即放弃锁前,就得先把其他可能阻塞的线程激活,避免出现所有线程都阻塞的状态 conB.signal(); conC.signal(); conA.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("A" + k); threadName = "B"; conB.signal(); } finally { // 自己释放锁,就会进入同步队列;和调用await进入等待队列是不同的;前者释放锁后仍然可以加入锁竞争 lock.unlock(); } } } } class ThreadB implements Runnable { @Override public void run() { for(int k=1; k<=10; k++) { lock.lock(); try { while (!threadName.equals("B")) { try { conC.signal(); conA.signal(); conB.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("B" + k); threadName = "C"; conC.signal(); } finally { lock.unlock(); } } } } class ThreadC implements Runnable { @Override public void run() { for(int k=1; k<=10; k++) { lock.lock(); try { while (!threadName.equals("C")) { try { conA.signal(); conB.signal(); conC.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("C" + k); threadName = "A"; conA.signal(); } finally { lock.unlock(); } } } } }三个线程轮流输出从1-100
package tacos.thread; import org.junit.Test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadDemo2 { public volatile static AtomicInteger num = new AtomicInteger(0); public static Lock lock = new ReentrantLock(); public static Condition conA = lock.newCondition(); public static Condition conB = lock.newCondition(); public static Condition conC = lock.newCondition(); @Test public void test() { ExecutorService es = Executors.newFixedThreadPool(3); es.execute(new ThreadA()); es.execute(new ThreadB()); es.execute(new ThreadC()); // 单独运行test()方法时,当前线程需要暂停一段时间才能保证顺利输出到100; // 如果把整个java项目启动运行起来,就不需要下面暂停当前线程这一步 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } es.shutdown(); } class ThreadA implements Runnable { @Override public void run() { while(true) { lock.lock(); try { while (num.get() % 3 != 0) { try { conB.signal(); conC.signal(); conA.await(); } catch (InterruptedException e) { e.printStackTrace(); } } if(num.get() > 99) { break; } System.out.println(Thread.currentThread().getName() + " " + (num.getAndIncrement() + 1)); conB.signal(); } finally { lock.unlock(); } } } } class ThreadB implements Runnable { @Override public void run() { while(true) { lock.lock(); try { while (num.get() % 3 != 1) { try { conC.signal(); conA.signal(); conB.await(); } catch (InterruptedException e) { e.printStackTrace(); } } if(num.get() > 99) { break; } System.out.println(Thread.currentThread().getName() + " " + (num.getAndIncrement() + 1)); conC.signal(); } finally { lock.unlock(); } } } } class ThreadC implements Runnable { @Override public void run() { while(true) { lock.lock(); try { while (num.get() % 3 != 2) { try { conA.signal(); conB.signal(); conC.await(); } catch (InterruptedException e) { e.printStackTrace(); } } if(num.get() > 99) { break; } System.out.println(Thread.currentThread().getName() + " " + (num.getAndIncrement() + 1)); System.out.println(); conA.signal(); } finally { lock.unlock(); } } } } }Java核心技术卷I上的内容
conA.await():
1)当前线程会暂停,并放弃锁,此时其他线程就有可能获取锁并执行。等待获取锁的线程(在同步队列中)和已经调用了await方法的线程(在conA对应的等待队列中)本质上就不同;因为一个线程一旦调用await方法,就会释放锁并进入等待队列,当锁可用时这个线程也不会变为可运行状态去竞争锁,而是仍保持非活动状态,知道另一个线程在conA这个条件上调用singal或者singalAll方法。
2)如果另一个线程在conA这个条件上调用singal或者singalAll方法,conA等待队列中的线程就会从等待队列中移出,进入同步队列,重新变为可运行的线程。同时,它们会重新进入该对象(也就是重新竞争锁),一旦锁可用(竞争到了锁),他们中的某个线程将从await调用返回,得到这个锁,并从之前暂停的地方继续执行。
conA.singalAll():
1)最终需要有某个其他线程调用singalAll方法,这一点至关重要。当一个线程调用await时,它没有办法重新自行激活。它寄希望于其他线程。如果没有其他线程来重新激活等待队列中的线程,它们就永远不会执行了。所以如果其他线程都进入了各自的等待队列(被阻塞),最后一个活动线程(拿到了锁或者还在同步队列中)调用了await方法但没有先解除另外某个线程的阻塞,现在这个线程也会阻塞。此时没有线程可以解除其他线程的阻塞状态,所以线程都挂起,程序gg。注意:只有当线程拥有一个条件的锁时,它才能在这个条件上调用await,singalAll或singal。
2)注意的一点是singalAll调用不会立即激活一个等待的线程。它只是解除等待线程的阻塞,使这些线程可以在当前线程释放锁之后竞争访问对象。
package tacos.thread; import org.junit.Test; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ThreadDemo3 { @Test public void test() { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1); scheduledThreadPool.schedule(new Thread3(), 3, TimeUnit.SECONDS); scheduledThreadPool.schedule(new Thread1(), 1, TimeUnit.SECONDS); scheduledThreadPool.schedule(new Thread6(), 6, TimeUnit.SECONDS); try { Thread.sleep(12000); } catch (InterruptedException e) { e.printStackTrace(); } scheduledThreadPool.shutdown(); } class Thread1 implements Runnable{ @Override public void run() { System.out.println("延迟1s"); } } class Thread3 implements Runnable{ @Override public void run() { System.out.println("延迟3s"); } } class Thread6 implements Runnable{ @Override public void run() { System.out.println("延迟6s"); } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)