import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadCaseTest {
static ReentrantLock lock = new ReentrantLock();
static final Object o = new Object(); //共享变量
static volatile int num = 0; //volatile 多线程情况下保证数据的可见性
static final int ticketNums = 100; //总票数
static final int peopleSize = 200; //抢票人数
static int ticketNum;//票数
static int peopleNum;//人数
static String code = "A"; //默认是A
public static void main(String[] args) throws Exception {
demo1();
demo2();
demo3();
demo4();
demo5();
demo6();
demo7();
demo8();
}
/**
* 8. 两个线程交替打印奇偶数。0-100
*/
private static void demo8() {
Condition a = lock.newCondition();
Condition b = lock.newCondition();
new Thread(() -> {
while (num < 100) {
try {
lock.lock();
if (num % 2 == 1) {
a.await();//当前线程等待
}
System.out.println(Thread.currentThread().getName() + num);
num++;
b.signal();//唤醒另一个线程
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//释放锁
}
}
}, "线程A: ").start();
new Thread(() -> {
while (num < 100) {
try {
lock.lock();
if (num % 2 == 0) {
b.await();
}
System.out.println(Thread.currentThread().getName() + num);
num++;
a.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "线程B: ").start();
}
/**
* 7. 抢票案例
*/
private static void demo7() {
new TicketThread("窗口A").start();
new TicketThread("窗口B").start();
new TicketThread("窗口C").start();
new TicketThread("窗口D").start();
}
/**
* 6. 哲学家就餐问题
*/
private static void demo6() {
Chopsticks chopsticks0 = new Chopsticks();
Chopsticks chopsticks1 = new Chopsticks();
Chopsticks chopsticks2 = new Chopsticks();
Chopsticks chopsticks3 = new Chopsticks();
Chopsticks chopsticks4 = new Chopsticks();
new Philosohper("哲学家1", 1, chopsticks0, chopsticks1).start();
new Philosohper("哲学家2", 2, chopsticks1, chopsticks2).start();
new Philosohper("哲学家3", 3, chopsticks2, chopsticks3).start();
new Philosohper("哲学家4", 4, chopsticks3, chopsticks4).start();
new Philosohper("哲学家5", 5, chopsticks4, chopsticks0).start();
}
/**
* 5. 三个线程 a、b、c 并发运行,b,c 需要 a 线程的数据怎么实现
*/
private static void demo5() {
new Thread(() -> {
try {
//模拟耗时操作之后初始化变量 num
Thread.sleep(1000);
num = 1;
System.out.println(Thread.currentThread().getName() + "获取到 num 的值为:" + num);
} catch (Exception e) {
e.printStackTrace();
}
}, "线程A:").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "获取到 num 的值为:" + num);
}, "线程B:").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "获取到 num 的值为:" + num);
}, "线程C:").start();
}
/**
* 4. 三个线程的Name分别是A,B,C;每个线程将自己的Name在控制台上打印5遍,打印顺序是ABC ABC...
*/
private static void demo4() {
Condition a = lock.newCondition();
Condition b = lock.newCondition();
Condition c = lock.newCondition();
printA(a, b);
printB(b, c);
printC(c, a);
}
/**
* 3. 写两个线程,一个线程打印1~ 52,另一个线程打印A~Z,打印顺序是12A34B...5152Z
* 字母个数:26 A~Z。大写字母的A是65开始的,对应ASCII码表
*/
private static void demo3() {
new Thread(() -> {
synchronized (o) {
try {
while (num < 52) {
num++;
System.out.println(Thread.currentThread().getName() + num);
if (num % 2 == 0) {
o.notify();
o.wait();
}
}
o.notify();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "线程A:").start();
new Thread(() -> {
synchronized (o) {
try {
for (int i = 0; i < 26; i++) {
System.out.println(Thread.currentThread().getName() + (char) (65 + i));
o.notify();
o.wait();
}
o.notify();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "线程B:").start();
}
/**
* 2. 两个线程轮流打印数字,一直到100。t1:1,t2:2;t1:3,t2:4;......
*/
private static void demo2() {
new Thread(() -> {
synchronized (o) {
while (num < 100) {
try {
num++;
System.out.println(Thread.currentThread().getName() + num);
o.notify();
o.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
o.notify();
}
}, "线程A: ").start();
new Thread(() -> {
synchronized (o) {
while (num < 100) {
try {
num++;
System.out.println(Thread.currentThread().getName() + num);
o.notify();
o.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
o.notify();
}
}, "线程B: ").start();
}
/**
* 1. 要求线程a执行完才开始线程b, 线程b执行完才开始线程c
*
* @throws Exception
*/
private static void demo1() throws Exception {
PrintThread threadA = new PrintThread("A");
PrintThread threadB = new PrintThread("B");
PrintThread threadC = new PrintThread("C");
threadA.start();
threadA.join();
threadB.start();
threadB.join();
threadC.start();
threadC.join();
}
static class PrintThread extends Thread {
PrintThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
private static void printA(Condition a, Condition b) {
new Thread(() -> {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
if (!code.equalsIgnoreCase("A")) a.await();
System.out.println(Thread.currentThread().getName() + i);
code = "B";
b.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "线程A:").start();
}
private static void printB(Condition b, Condition c) {
new Thread(() -> {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
if (!code.equalsIgnoreCase("B")) b.await();
System.out.println(Thread.currentThread().getName() + i);
code = "C";
c.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "线程B:").start();
}
private static void printC(Condition c, Condition a) {
new Thread(() -> {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
if (!code.equalsIgnoreCase("C")) c.await();
System.out.println(Thread.currentThread().getName() + i);
code = "A";
a.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "线程C:").start();
}
static class Philosohper extends Thread {
private String name;//名字
private int num;//编号
private Chopsticks left, right;//筷子
Philosohper(String name, int num, Chopsticks left, Chopsticks right) {
this.name = name;
this.num = num;
this.left = left;
this.right = right;
}
@Override
public void run() {
if (num % 2 == 0) { //假设有人是左撇子
synchronized (left) {
try {
sleep(1000);
synchronized (right) {
System.out.println("编号为:" + num + " 名字为:" + name + " 开始吃饭了");
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
synchronized (right) {
try {
sleep(1000);
synchronized (left) {
System.out.println("编号为:" + num + " 名字为:" + name + " 开始吃饭了");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
static class Chopsticks {
}
static class TicketThread extends Thread {
private String windowName;
TicketThread(String windowName) {
this.windowName = windowName;
}
@Override
public void run() {
synchronized (o) {
while (ticketNum < ticketNums && peopleNum < peopleSize) {
if (peopleNum % 2 == 1) {
System.out.println(windowName + " " + Thread.currentThread().getName() + " 第" + (++peopleNum) + "个人抢到第" + (++ticketNum) + " 张票");
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println(windowName + " " + Thread.currentThread().getName() + " 第" + (++peopleNum) + " 个人未抢到票");
}
}
}
}
}
}
Java 采用ReentrantLock和Synchronized实现多线程案例(哲学家就餐问题、多个线程交替打印、抢票案例)
于 2023-06-21 15:15:18 首次发布