线程之示例
一.多种方式解决一个生产者与消费者问题
二.交替打印问题
1.A、B两个线程交替打印1 -- 100
2.Java实现两个线程交替打印问题
3.java多线程交替打印A和B?
4.java多线程 更优雅的实现线程同步:交替打印A、B LockSupport实现
一. 如何解决一个生产者与消费者问题
多线程同步经典问题。生产者和消费者同时使用一块缓冲区,生产者生产商品放入缓冲区,消费者从缓冲区中取出商品。需要保证是,当缓冲区满时,生产者不可生产商品;当缓冲区为空时,消费者不可取出商品。
几种解决同步问题的方式
(1)wait()与notify()
(2)Lock与Condition机制
(3)BlockingQueue阻塞队列
【1】object类的wait()与notify()方法
wait()用在以下场合:
(1)当缓冲区满时,缓冲区调用wait()方法,使得生产者释放锁,当前线程阻塞,其他线程可以获得锁。
(2)当缓冲区空时,缓冲区调用wait()方法,使得消费者释放锁,当前线程阻塞,其他线程可以获得锁。
notify()用在以下场合:
(1)当缓冲区未满时,生产者生产商品放入缓冲区,然后缓冲区调用notify()方法,通知上一个因wait()方法释放锁的线程现在可以去获得锁了,同步块代码执行完成后,释放对象锁,此处的对象锁,锁住的是缓冲区。
(2)当缓冲区不为空时,消费者从缓冲区中取出商品,然后缓冲区调用notify()方法,通知上一个因wait()方法释放锁的线程现在可以去获得锁了,同步块代码执行完成后,释放对象锁。
// 生产者消费者问题
public class ProAndCon {
public static final int MAX_SIZE = 2;
public static LinkedList<Integer> list = new LinkedList<>();
class Producer implements Runnable {
public void run() {
synchronized (list) {
//仓库容量已经达到最大值
while (list.size() == MAX_SIZE) {
System.out.println("仓库已满,生产者" + currentThread().getName() + "不可生产.");
try {
list.wait();
}
}
list.add(1);
System.out.println("生产者" + currentThread().getName() + "生产, 仓库容量为" + list.size());
list.notify();
}}}
class Consumer implements Runnable {
public void run() {
synchronized (list) {
while (list.size() == 0) {
System.out.println("仓库为空,消费者" + currentThread().getName() + "不可消费");
try {
list.wait();
}
}
list.removeFirst();
System.out.println("消费者" + currentThread().getName() + "消费,仓库容量为" + list.size());
list.notify();
}}
}
public static void main(String[] args) {
ProAndCon proAndCon = new ProAndCon();
Producer producer = proAndCon.new Producer();
Consumer consumer = proAndCon.new Consumer();
for (int i = 0; i < 10; i++) {
Thread pro = new Thread(producer);
pro.start();
Thread con = new Thread(consumer);
con.start();
}}}
【2】Lock与Condition机制
JDK5.0之后,Java提供Lock与Condition机制。Condition接口的await()和signal()是做同步的两种方法,它们功能基本上和Object的wait()、nofity()相同,或者说可以取代它们,但是它们和Lock机制是直接挂钩的。
通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。
public class ProAndCon2 {
public static final int MAX_SIZE = 2;
public static LinkedList<Integer> list = new LinkedList<>();
public static Lock lock = new ReentrantLock();
//仓库满的条件变量
public static Condition full = lock.newCondition();
//仓库空的条件变量
public static Condition empty = lock.newCondition();
class Producer implements Runnable {
public void run() {
lock.lock();
while (list.size() == MAX_SIZE) {
try {
System.out.println("仓库已满,生产者" +currentThread().getName() + "不可生产.");
full.await();
}
}
list.add(1);
System.out.println("生产者" + currentThread().getName() + "生产, 仓库容量为" + list.size());
//唤醒其他生产者与消费者线程
full.signal();
empty.signal();
lock.unlock();}
}
class Consumer implements Runnable {
public void run() {
lock.lock();
while (list.size() == 0) {
try {
System.out.println("仓库为空,消费者" +currentThread().getName() + "不可消费.");
empty.await();
}
}
list.removeFirst();
System.out.println("消费者" +currentThread().getName() + "消费,仓库容量为" + list.size());
//唤醒其他生产者与消费者线程
full.signal();
empty.signal();
lock.unlock();
}}
public static void main(String[] args) {
ProAndCon2 proAndCon = new ProAndCon2();
Producer producer = proAndCon.new Producer();
Consumer consumer = proAndCon.new Consumer();
for (int i = 0; i < 10; i++) {
Thread pro = new Thread(producer);
pro.start();
Thread con = new Thread(consumer);
con.start();
}
}}
【3】使用BlockingQueue阻塞队列
什么是阻塞队列?
如果向一个已经满了的队列中添加元素或者从空队列中移除元素,都将会导致线程阻塞,线程一直等待到有旧元素被移除或新元素被添加的时候,才能继续执行。
JDK 1.5 以后新增BlockingQueue接口,我用它实现类,ArrayBlockingQueue或者是LinkedBlockingQueue。
怎么使用LinkedBlockingQueue?
用LinkedBlockingQueue来解决生产者与消费者问题,主要用到它put()与take()
put():向阻塞队列中添加一个元素,队列满时,自动阻塞。
take():从阻塞队列中取出一个元素,队列空时,自动阻塞。
原理:其实LinkedBlockingQueue底层使用的仍然是Lock与Condition机制,从源码知道
//..............用到了Lock与Condition机制。 LinkedBlockingQueue底层已经解决好了同步问题,可方便使用它。
// 解决生产者与消费者问题: 采用阻塞队列BlockingQueue
public class ProAndCon3 {
public static final int MAX_SIZE = 2;
public static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(MAX_SIZE);
class Producer implements Runnable {
public void run() {
if (queue.size() == MAX_SIZE) {
System.out.println("仓库已满,生产者" + currentThread().getName() + "不可生产.");
}
try {
queue.put(1);
System.out.println("生产者" +currentThread().getName() + "生产, 仓库容量为" + queue.size());
}
}}
class Consumer implements Runnable {
public void run() {
if (queue.size() == 0) {
System.out.println("仓库为空,消费者" + currentThread().getName() + "不可消费.");
}
try {
queue.take();
System.out.println("消费者" + currentThread().getName() + "消费,仓库容量为" + queue.size());
}
}}
public static void main(String[] args) {
ProAndCon3 proAndCon = new ProAndCon3();
Producer producer = proAndCon.new Producer();
Consumer consumer = proAndCon.new Consumer();
for (int i = 0; i < 10; i++) {
Thread pro = new Thread(producer);
pro.start();
Thread con = new Thread(consumer);
con.start();
}}}
二. 多线程交替打印问题
2.1. 多线程交替打印A和B?
关键就是打印A和B的方法,synchronized的对象是同一个,即持有的锁是同一个,都是print这个类的实例
然后又一个标志,当不是自己的时候,就释放自己的锁,并让线程进入等待状态,就是this.wait()
当while执行完后,说明到自己的回合,打印字符,设置标志,然后唤醒锁为this的线程。
class Print{
boolean nowA=true;
synchronized void printA(){
while(!nowA){
try {
this.wait();
}
}
nowA=false;
System.out.println(Thread.currentThread()+""+"A");
this.notify();
}
synchronized void printB(){
while(nowA){
try {
this.wait();
}
}
nowA=true;
System.out.println(Thread.currentThread()+" "+"B");
this.notify();
}}
public class Test3 {
public static void main(String[] args){
Print print=new Print();
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++){
print.printA();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++){
print.printB();
}
}
}).start();;
}}
2.2 .java多线程 更优雅的实现线程同步:交替打印A、B LockSupport实现
一 问题概述
线程或者进程之间有两种关系:同步和互斥,通常实现同步方法是使用线程的等待唤醒机制,而等待唤醒机制使用是建立在互斥继承上的。
但是同步线程并不一定是必须要实现互斥的。比如一个线程打印A,一个线程打印B。这两个线程就没有互斥关系,但是提出这么个需求:交替打印A、B ,
一般往往要使用wait()/notify机制。
二 LockSupport 介绍
LockSupport作为一个工具类,主要学习它的方法。
park():在线程内调用,表示当前线程自我阻塞,直到获得许可证
park(线程变量):让指定的线程获得许可证。
一看这两个方法的定义,显然可以利用这两个方法实现线程的顺序调用(同步)
三 两种思路实现交替打印A/B
* 交替打印A/B 等待唤醒机制
public class Test3 {
static class MyRun implements Runnable {
static int i = 0;
@Override
public synchronized void run() {
for (int j = 0; j < 10; j++) {
if(i%2==0)
System.out.println(Thread.currentThread().getName()+":A");
else
System.out.println(Thread.currentThread().getName()+":B");
i++;
this.notifyAll();
try {
if(i>=19)
Thread.sleep(10);
else
this.wait();
} }
}}
public static void main(String[] args) {
MyRun myRun = new MyRun();
Thread a = new Thread(myRun);
Thread b = new Thread(myRun);
a.start();
b.start();
}}
//LockSupport实现: 交替打印A,B LockSupport实现
public class Test2 {
static Thread a=null;
static Thread b=null;
public static void main(String[] args) {
a= new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LockSupport.park();
System.out.println(currentThread().getName()+":B");
LockSupport.unpark(b);
}
}});
b=new Thread((new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(currentThread().getName()+":A");
LockSupport.unpark(a);
LockSupport.park();
}
}}));
a.start();
b.start();
}}
2.3 Java实现两个线程交替打印问题
线程1负责打印a,b,c,d
线程2负责打印1,2,3,4;要求控制台中输出的内容为 a1b2c3d4
public class TestMain {
static final Object object = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
String a[] = {"a","b","c","d"};
@Override
public void run() {
for(int i=0;i< 4 ;i++){
synchronized (object){
System.out.println("线程a 开始执行");
object.notify();
try {
System.out.println("线程a 开始等待");
object.wait();
}
System.out.println("线程a 继续执行");
System.out.println(a[i]);
System.out.println("线程a 执行结束");
object.notify();
}}
}}).start();
new Thread(new Runnable() {
int a[] = {1,2,3,4};
@Override
public void run() {
for(int i=0;i<4;i++){
synchronized (object){
System.out.println("线程1 开始执行");
object.notify();
try {
System.out.println("线程1 开始等待");
object.wait();
}
System.out.println("线程1 继续执行");
System.out.println(a[i]);
System.out.println("线程1 执行结束");
}
} }}).start();
}}
2.4 .A、B两个线程交替打印1 -- 100
方案一:
public class Test100_02 {
private static Object object = new Object();
private static boolean isFlag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 1; i <= 999; i+=2) {
synchronized (object) {
if (!isFlag) {
System.out.println("current:" + i);
isFlag = true;
try {
object.wait();
}
object.notify();
}
}
}});
Thread t2 = new Thread(() -> {
for (int i = 2; i <= 1000; i+=2) {
synchronized (object) {
if (isFlag) {
isFlag = false;
System.out.println("current:" + i);
object.notify();
try {
object.wait();
} }
}}
});
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}}
方案二:
public class Test100_01 {
private static Lock lock = new ReentrantLock();
private static Condition condition1 = lock.newCondition();
private static Condition condition2 = lock.newCondition();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 1; i <= 999; i += 2) {
lock.lock();
try {
System.out.println("current:" + i);
condition1.await();
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}});
Thread t2 = new Thread(() -> {
for (int i = 2; i <= 1000; i += 2) {
lock.lock();
try {
System.out.println("current:" + i);
condition1.signal();
condition2.await();
}
lock.unlock();
}
});
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}}
你的代码我运行了貌似会在中途卡住,
我改进了一下顺序
condition2.signal();
System.out.println("current:" + i);
condition1.await();
condition1.signal();
System.out.println("current:" + i);
condition2.await();
41.生产者消费者模式
class Clerk {//店员类
private int product = 0;
public synchronized void get() {// 进货
while (product >= 1) {
System.out.println("产品已满!");
try {
this.wait();}
}
System.out.println(currentThread().getName() + ":" + ++product);
this.notifyAll(); // 唤醒
}
public synchronized void sale() {// 售货
while (product <= 0) {
System.out.println("缺货!");
try {
this.wait();// 等待}
}
System.out.println(currentThread().getName() + ":" + --product);
this.notifyAll();// 唤醒}
}
class Productor implements Runnable {// 生产者类
private Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
}
clerk.get();}
}
}
class Consumer implements Runnable {// 消费者类
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
clerk.sale();
}}
}
public class TestProductorAndConsumer {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor productor = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(productor, "Productor A").start();
new Thread(consumer, "Consumer B").start();
new Thread(productor, "Productor C").start();
new Thread(consumer, "Consumer D").start(); }
}
42.线程交替打印
//其他方法: https://segmentfault.com/a/1190000021433079?utm_source=sf-similar-article
//**** 1) 3个线程交替打印0->100
public class Main012 {
public static void main(String[] args) {
int threadCount = 3;
int max = 100;
for (int i = 0; i < threadCount; i++) {
new Thread(new PrintSequenceThread(i, threadCount, max)).start();}
}
}
class PrintSequenceThread implements Runnable {
private static final Object mLock = new Object();
private static int current = 0;//当前即将打印的数字
private int threadNo;//前线程编号,从0开始
private int threadCount;
private int max;//打印的最大值
public PrintSequenceThread(int threadNo, int threadCount, int max) {
this.threadNo = threadNo;
this.threadCount = threadCount;
this.max = max;
}
public void run() {
while (true) {
synchronized (mLock) {
// 判断是否轮到当前线程执行
while (current % threadCount != threadNo) {
if (current > max) {break;}
try {
mLock.wait();// 如果不是,则当前线程进入wait
}
}
// 最大值跳出循环
if (current > max) {break;}
System.out.println("thread-" + threadNo + " : " + current);
current++;
mLock.notifyAll(); //唤醒其他wait线程
}
}}
}
//************
//2) 3个线程并发打印从0到n,不是交替打印,每个线程可能连续执行,有的线程可能长时间按得不到执行
public class Main12_1 {
public static void main(String[] args) {
int threadCount = 3;
for (int i = 0; i < threadCount; i++) {
new Thread(new PrintSequenceThread1(i, threadCount)).start();
}
}
}
class PrintSequenceThread1 implements Runnable {
private static final Object mLock = new Object();
private static int current = 0; // 当前即将打印的数字
private int threadNo; // 当前线程编号,从0开始
private int threadCount;
public PrintSequenceThread1(int threadNo, int threadCount) {
this.threadNo = threadNo;
this.threadCount = threadCount;
}
@Override
public void run() {//3个线程并发打印从0到n,不是交替打印,每个线程可能连续执行,有的线程可能长时间按得不到执行
while (true) {
synchronized (mLock) {
try {
Thread.sleep(100);
}
System.out.println("thread-" + threadNo + " : " + current);
current++;
}}
}
}
//**** 3) 3个线程交替打印从0到n
public class Main12_2 {
public static void main(String[] args) {
int threadCount = 3;
for (int i = 0; i < threadCount; i++) {
//3个线程交替打印从0到n
new Thread(new PrintSequenceThread2(i, threadCount)).start();
}}
}
class PrintSequenceThread2 implements Runnable {
private static final Object mLock = new Object();
private static int current = 0;//当前即将打印的数字
private int threadNo;// 当前线程编号,从0开始
private int threadCount;//线程数量
public PrintSequenceThread2(int threadNo, int threadCount) {
this.threadNo = threadNo;
this.threadCount = threadCount;
}
public void run() {//3个线程交替打印从0到n
while (true) {
synchronized (mLock) {
// 判断是否轮到当前线程执行
while (current % threadCount != threadNo) {//一定是while,而不是if
try {
//是while的原因,当这个线程被notifyAll时,它会从mLock.wait()这句之后继续往下执行,即使当前没有轮到它
//写成while,如果它依然满足条件(没有轮到它),它会一直阻塞在这里
// 如果不是,则当前线程进入wait
mLock.wait();
}
}
try {
Thread.sleep(100);//停顿100ms,为了让打印不要太快
}
System.out.println("thread-" + threadNo + " : " + current);
current++;
mLock.notifyAll();}
}
}
}
二. 三个线程交替打印ABC
如果要实现3个线程交替打印ABC呢?这次打算使用重入锁,和上面没差多少,但是由于现在有三个线程了,在打印完后需要唤醒其他线程,注意不可使用sigal(),因为唤醒的线程是随机的,不能保证打印顺序不说,还会造成死循环。一定要使用sigalAll()唤醒所有线程。
public class ThreeThreadPrintABC {
private static ReentrantLock lock = new ReentrantLock();
private static Condition wait = lock.newCondition();
// 用来控制该打印的线程
private static int count = 0;
static class PrintA implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while ((count % 3) != 0) {
wait.await();
}
System.out.println(Thread.currentThread().getName() + " A");
count++;
wait.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
static class PrintB implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while ((count % 3) != 1) {
wait.await();
}
System.out.println(Thread.currentThread().getName() + " B");
count++;
wait.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
static class PrintC implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while ((count % 3) != 2) {
wait.await();
}
System.out.println(Thread.currentThread().getName() + " C");
count++;
wait.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
Thread printA = new Thread(new PrintA());
Thread printB = new Thread(new PrintB());
Thread printC = new Thread(new PrintC());
printA.start();
printB.start();
printC.start();
}
}
Thread-0 A
Thread-1 B
Thread-2 C
Thread-0 A
Thread-1 B
Thread-2 C
Thread-0 A
Thread-1 B
Thread-2 C
Thread-0 A
Thread-1 B
Thread-2 C
如果觉得不好理解,重入锁是可以绑定多个条件的。创建3个Condition分别让三个打印线程在上面等待。A打印完了,唤醒等待在conditionB对象上的PrintB;B打印完了唤醒在conditionC对象上的PrintC;C打印完了,唤醒在conditionA对象上等待的PrintA,如此循环地唤醒对方即可。
public class ThreeThreadPrintABC1 {
private static ReentrantLock lock = new ReentrantLock();
private static Condition conditionA = lock.newCondition();
private static Condition conditionB = lock.newCondition();
private static Condition conditionC = lock.newCondition();
// 用来控制该打印的线程
private static int count = 0;
static class PrintA implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (count % 3 != 0) {
conditionA.await();
}
System.out.println(Thread.currentThread().getName() + "------A");
count++;
conditionB.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
static class PrintB implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (count % 3 != 1) {
conditionB.await();
}
System.out.println(Thread.currentThread().getName() + "------B");
count++;
conditionC.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
static class PrintC implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (count % 3 != 2) {
conditionC.await();
}
System.out.println(Thread.currentThread().getName() + "------C");
count++;
conditionA.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
Thread printA = new Thread(new PrintA());
Thread printB = new Thread(new PrintB());
Thread printC = new Thread(new PrintC());
printA.start();
printB.start();
printC.start();
}
}
Thread-0------A
Thread-1------B
Thread-2------C
Thread-0------A
Thread-1------B
Thread-2------C
Thread-0------A
Thread-1------B
Thread-2------C
Thread-0------A
Thread-1------B
Thread-2------C
另一种实现:
/**
* 基于一个ReentrantLock和三个conditon实现连续打印abcabc...
*/
public class PrintABCTest implements Runnable {
// 打印次数
private static final int PRINT_COUNT = 10;
// 打印锁
private final ReentrantLock lock;
// 本线程打印所需的condition
private final Condition thisCondition;
// 下一个线程打印所需的condition
private final Condition nextCondition;
// 打印字符
private final char printChar;
public PrintABCTest(ReentrantLock lock, Condition thisCondition, Condition nextCondition, char printChar) {
this.lock = lock;
this.thisCondition = thisCondition;
this.nextCondition = nextCondition;
this.printChar = printChar;
}
@Override
public void run() {
// 获取打印锁 进入临界区
lock.lock();
try {
// 连续打印PRINT_COUNT次
for (int i = 0; i < PRINT_COUNT; i++) {
//打印字符
System.out.println(printChar);
// 使用nextCondition唤醒下一个线程
// 因为只有一个线程在等待,所以signal或者signalAll都可以
nextCondition.signal();
// 不是最后一次则通过thisCondtion等待被唤醒
// 必须要加判断,不然虽然能够打印10次,但10次后就会直接死锁
if (i < PRINT_COUNT -1) {
try {
// 本线程让出锁并等待唤醒
thisCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} finally {
// 释放打印锁
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
// 写锁
ReentrantLock lock = new ReentrantLock();
// 打印a线程的condition
Condition conditionA = lock.newCondition();
// 打印b线程的condition
Condition conditionB = lock.newCondition();
// 打印c线程的condition
Condition conditionC = lock.newCondition();
// 实例化A线程
Thread printerA = new Thread(new PrintABCTest(lock, conditionA, conditionB, 'A'));
// 实例化B线程
Thread printerB = new Thread(new PrintABCTest(lock, conditionB, conditionC, 'B'));
// 实例化C线程
Thread printerC = new Thread(new PrintABCTest(lock, conditionC, conditionA, 'C'));
// 依次开始A B C线程
printerA.start();
Thread.sleep(100);
printerB.start();
Thread.sleep(100);
printerC.start();
}
}
A
B
C
A
B
C
A
B
C
A
B
C
一.两个线程交替打印奇偶数
方法1:使用同步方法实现
public class Num {
private int count = 1;
public synchronized void printOdd() {//打印奇数
try {
if (count % 2 != 1) {
this.wait();
}
System.out.println(Thread.currentThread().getName() + "----------" + count);
count++;
this.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printEven() {//打印偶数
try {
if (count % 2 != 0) {
this.wait();
}
System.out.println(Thread.currentThread().getName() + "----------" + count);
count++;
this.notify();
} catch (InterruptedException e) {
}
}
}
/**
* 打印奇数的线程
*/
public class Odd implements Runnable{
private Num num;
public Odd(Num num) {
this.num = num;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
num.printOdd();
}
}
}
/**
* 打印偶数的线程
*/
public class Even implements Runnable {
private Num num;
public Even(Num num) {
this.num = num;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
num.printEven();
}
}
}
public class TestPrint {
public static void main(String[] args) {
Num num = new Num();
Odd odd = new Odd(num);
Even even = new Even(num);
Thread t1 = new Thread(odd, "threadOdd");
Thread t2 = new Thread(even, "threadEven");
t1.start();
t2.start();
}
}
threadOdd----------1
threadEven----------2
threadOdd----------3
threadEven----------4
threadOdd----------5
threadEven----------6
threadOdd----------7
threadEven----------8
threadOdd----------9
threadEven----------10
方法2:使用同步块实现
public class Number {
private int count = 1;
private Object lock = new Object();
public void printOdd() {//打印奇数
synchronized(lock) {
try {
if(count % 2 != 1) {
lock.wait();
}
System.out.println(Thread.currentThread().getName() + "=======" + count);
count++;
lock.notify();
} catch(InterruptedException e) {
}
}
}
public void printEven() {//打印偶数
synchronized(lock) {
try {
if(count % 2 != 0) {
lock.wait();
}
System.out.println(Thread.currentThread().getName() + "=======" + count);
count++;
lock.notify();
} catch(InterruptedException e) {
}
}
}
}
/**
* 打印奇数的线程
*/
public class OddPrinter implements Runnable {
private Number num;
public OddPrinter(Number num) {
this.num = num;
}
public void run() {
for (int i = 0; i < 5; i++) {
num.printOdd();
}
}
}
/**
* 打印偶数的线程
*/
public class EvenPrinter implements Runnable{
private Number num;
public EvenPrinter(Number num) {
this.num = num;
}
public void run() {
for (int i = 0; i < 5; i++) {
num.printEven();
}
}
}
public class PrintOddEven {
public static void main(String[] args) {
Number num = new Number();
OddPrinter oddPrinter = new OddPrinter(num);
EvenPrinter evenPrinter = new EvenPrinter(num);
Thread oddThread = new Thread(oddPrinter, "oddThread");
Thread evenThread = new Thread(evenPrinter, "evenThread");
oddThread.start();
evenThread.start();
}
}
oddThread=======1
evenThread=======2
oddThread=======3
evenThread=======4
oddThread=======5
evenThread=======6
oddThread=======7
evenThread=======8
oddThread=======9
evenThread=======10
方法3:使用ReentrantLock实现
public class Number1 {
private int count = 1;
private ReentrantLock lock = new ReentrantLock();
// 为打印奇数的线程注册一个Condition
public Condition conditionOdd = lock.newCondition();
// 为打印偶数的线程注册一个Condition
public Condition conditionEven = lock.newCondition();
public void printOdd() {//打印奇数
try {
lock.lock();
if(count % 2 != 1) {
conditionOdd.await();
}
System.out.println(Thread.currentThread().getName() + "=======" + count);
count++;
conditionEven.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printEven() {//打印偶数
try {
lock.lock();
if(count % 2 != 0) {
conditionEven.await();
}
System.out.println(Thread.currentThread().getName() + "=======" + count);
count++;
conditionOdd.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class PrintOddEven1 {
public static void main(String[] args) {
final Number1 num = new Number1();
/**
* 打印奇数的线程
*/
Thread oddThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
num.printOdd();
}
}
}, "oddThread");
/**
* 打印偶数的线程
*/
Thread evenThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
num.printEven();
}
}
}, "evenThread");
oddThread.start();
evenThread.start();
}
}
oddThread=======1
evenThread=======2
oddThread=======3
evenThread=======4
oddThread=======5
evenThread=======6
oddThread=======7
evenThread=======8
oddThread=======9
evenThread=======10
浙公网安备 33010602011771号