- 三个线程轮流打印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");
}
}
}



