前言:以下问题还有答案均为过去我写博客写的总结,同时面试也可能会问,理解并真正的懂,勤于实践才是提高之本.
文章目录
求助
希望大佬帮帮看看题目十二我留下的疑惑
相关代码
链接:https://pan.baidu.com/s/1oHOXleCjdYyaf4Jsu5Zoag
提取码:rwhl
多线程容易出现的书写误区
共享变量的输出位置
//这个例子本想书写 2个线程一起买票,最后最缺a 线程单独 买 然后是 b单独买自己的.
class Mythread extends Thread{
private int count = 60;
@Override
public void run() {
while (count>0){
System.out.println(Thread.currentThread().getName()+"=====>"+(count--));
}
}
}
public class Demo {
public static void main(String[] args) {
new Mythread().start(); // 他
new Mythread().start();
}
}
输出结果
thread-01 60 减到 0
thread-02 60 减到 0
正确做法
class Resource{
public int count = 60;
}
class Mythread extends Thread{
Resource resource;
public Mythread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (resource.count>0){
System.out.println(Thread.currentThread().getName()+"=====>"+(resource.count--));
}
}
}
public class Demo {
public static void main(String[] args) {
Resource resource = new Resource();
new Mythread(resource).start(); // 他
new Mythread(resource).start();
}
}
两个线程一起买 60 减到 0
题目一:发送用户10W邮件,如何多线程提高效率
/**
* 目前公司有1万个个用户,现在公司需要做活动,给每一个用户发送一条祝福短信。
*/
class Message implements Runnable{
private List<Object> lists;
public Message(List<Object> lists) {
this.lists = lists;
}
@Override
public void run() {
for (int i = 0; i <lists.size() ; i++) {
System.out.println(Thread.currentThread().getName()+"发送邮件");
}
}
}
public class threadDemo {
public static void main(String[] args) {
ArrayList<Object> objects = new ArrayList<>();
for (int i = 0; i <1000 ; i++) {
objects.add(new Student());
}
List<List<Object>> lists = ListUtils.splitList(objects, 100);
for (List<Object> list : lists) {
Message message = new Message(list);
new Thread(message).start();
}
}
}
class Student{
}
public class ListUtils {
public static <T> List<List<T>> splitList(List<T>list, int pageSize) {
int listSize = list.size();
int page = (listSize + (pageSize - 1)) / pageSize;
List<List<T>>listArray = new ArrayList<List<T>>();
for (int i = 0; i<page; i++) {
List<T>subList = new ArrayList<T>();
for (int j = 0; j<listSize; j++) {
int pageIndex = ((j + 1) + (pageSize - 1)) / pageSize;
if (pageIndex == (i + 1)) {
subList.add(list.get(j));
}
if ((j + 1) == ((j + 1) * pageSize)) {
break;
}
}
listArray.add(subList);
}
return listArray;
}
总结反思:这里面因为没有涉及到共享变量所以考的就是基本大数据多线程的处理.
题目二:手写一个不安全的例子
初始代码
/**
* 你可能会发现多买了一张票,或者重复卖了一张
*/
class Ticket {
public int count = 60;
}
class saleThread implements Runnable {
Ticket ticket;
public saleThread(Ticket ticket) {
this.ticket = ticket;
}
public void run() {
while (ticket.count > 0) { //在这里没有同步机制.导致的多卖或者重复买
System.out.println(Thread.currentThread().getName() + "====>" + delNum());
}
}
public int delNum() {
return ticket.count -= 1;
}
}
public class ThreadMain {
public static void main(String[] args) {
Ticket ticket = new Ticket();
saleThread saleThread = new saleThread(ticket);
new Thread(saleThread, "aa").start();
new Thread(saleThread, "bb").start();
}
}
完善代码
class Ticket {
public AtomicInteger atomicInteger = new AtomicInteger(60);
}
class saleThread implements Runnable {
Ticket ticket;
public saleThread(Ticket ticket) {
this.ticket = ticket;
}
public void run() {
while (ticket.atomicInteger.get() > 0) {
String s = Thread.currentThread().getName() + "====>" + ticket.atomicInteger.decrementAndGet();
System.out.println(s);
}
}
}
public class ThreadMain {
public static void main(String[] args) throws InterruptedException {
Ticket ticket = new Ticket();
saleThread saleThread = new saleThread(ticket);
new Thread(saleThread, "aa").start();
new Thread(saleThread, "bb").start();
}
}
题目三:线程A做写对的操作,线程B读的操操作
class Student {
public String name;
public String sex;
public boolean flag;
public Student() {
}
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
// 每次在男女之间进行动态设置
class OutputThread extends Thread {
private Student student;
public OutputThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true) {
synchronized (student){
if (student.flag) {
student.sex = "boy";
student.name = "william";
student.flag = false;
} else {
student.sex = "girl";
student.name = "alice";
student.flag = true;
}
}
}
}
}
class InputThread extends Thread {
private Student student;
public InputThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true){
synchronized (student){
System.out.println(Thread.currentThread().getName()+"====>"+student.name+"---"+student.sex);
}
}
}
}
public class ThreadMain {
public static void main(String[] args) {
Student student = new Student();
new OutputThread(student).start();
new InputThread(student).start();
}
}
---我们会看到这样的记过Thread-1====>william---girl,核心的问题的所在就是
改善代码
class Student {
public volatile String name;
public volatile String sex;
public volatile boolean flag;
public volatile boolean waitFlag = false;
public Student() {
}
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
// 每次在男女之间进行动态设置
class OutputThread extends Thread {
private Student student;
public OutputThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true) {
synchronized (student) {
if (student.waitFlag) { 如果为false 进行正常进行设置,为true就等着
try {
student.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (student.flag) {
student.sex = "boy";
student.name = "william";
student.flag = false;
} else {
student.sex = "girl";
student.name = "alice";
student.flag = true;
}
student.waitFlag = true;
student.notify();
}
}
}
}
class InputThread extends Thread {
private volatile Student student;
public InputThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true) {
synchronized (student) {
if (!student.waitFlag){
try {
student.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "====>" + student.name + "---" + student.sex);
student.waitFlag = false;
student.notify();
}
}
}
}
public class ThreadMain {
public static void main(String[] args) {
Student student = new Student();
new OutputThread(student).start();
new InputThread(student).start();
}
}
过程解析:
- 当OutputThread,InputThread启动的时候,此时OutputThread,直接进行girl等属性的设置,此时InputThread启动的时候在wait,
- 当OutputThread设置完毕的时候,进行属性的更改(并不能影响InputThread,因为他已经在进入到了wait),但是此时OutputThread不能继续设置啦。因为OutputThread修改的属性让自己wait啦
- 当OutputThread唤醒的时候,此时InputThread继续执行输出结果,此时继续执行类似1的操作
题目四:A,B 两个线程同时输出
面试我的阿里真题哦
package 两个线程的输出;
/**
* 一个a线程输出奇数 b线程输出偶数
*/
class Res {
public boolean flag = false;
}
class AThread extends Thread {
Res res;
public AThread(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
for (int i = 1; i <= 100; i++) {
synchronized (res) {
if (res.flag) {
try {
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + "====奇数" + i);
}
res.flag = true;
res.notify();
}
}
break;
}
}
}
class BThread extends Thread {
Res res;
public BThread(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
for (int i = 1; i <= 100; i++) {
synchronized (res) {
if (!res.flag) {
try {
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "====偶数" + i);
}
res.flag = false;
res.notify();
}
}
break;
}
}
}
public class ThreadMain {
public static void main(String[] args) {
Res res = new Res();
new AThread(res).start();
new BThread(res).start();
}
}
题目五: 使用Lock对题目四进行改造
package 两个线程的输出;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 一个a线程输出奇数 b线程输出偶数
*/
class Res {
public boolean flag = false;
public Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
}
class AThread extends Thread {
Res res;
public AThread(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
for (int i = 1; i <= 100; i++) {
res.lock.lock();
if (res.flag) {
try {
res.condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + "====奇数" + i);
}
res.flag = true;
res.condition.signal();
res.lock.unlock();
}
break;
}
}
}
class BThread extends Thread {
Res res;
public BThread(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
for (int i = 1; i <= 100; i++) {
res.lock.lock();
if (!res.flag) {
try {
res.condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "====偶数" + i);
}
res.flag = false;
res.condition.signal();
res.lock.unlock();
}
break;
}
}
}
public class ThreadMain {
public static void main(String[] args) {
Res res = new Res();
new AThread(res).start();
new BThread(res).start();
}
}
题目六:多重condition的使用
写法一:
package 循环输出;
import sun.font.FontRunIterator;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* aa打印5次,然后bb打印10次,cc打印15次
* 紧接着
* aa打印5次,然后bb打印10次,cc打印15次
* 来10轮
*/
class Res {
public int number = 1;
public Lock lock = new ReentrantLock();
public Condition c1 = lock.newCondition();
public Condition c2 = lock.newCondition();
public Condition c3 = lock.newCondition();
}
class AA extends Thread {
Res res;
public AA(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.lock.lock();
if (res.number != 1) {
try {
res.c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
res.number = 2;
res.c2.signal();
res.lock.unlock();
break;
}
}
}
class BB extends Thread {
Res res;
public BB(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.lock.lock();
if (res.number != 2) {
try {
res.c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
res.number = 3;
res.c3.signal();
res.lock.unlock();
break;
}
}
}
class CC extends Thread {
Res res;
public CC(Res res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.lock.lock();
if (res.number != 3) {
try {
res.c3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
res.number = 1;
res.c1.signal();
res.lock.unlock();
break;
}
}
}
public class ThreadMain {
public static void main(String[] args) {
Res res = new Res();
for (int i = 0; i < 10; i++) {
AA aa = new AA(res);
aa.setName("aa");
aa.start();
BB bb = new BB(res);
bb.setName("bb");
bb.start();
CC cc = new CC(res);
cc.setName("cc");
cc.start();
}
}
}
写法二
class MyData {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increatement() throws InterruptedException {
lock.lock();
try {
while (number != 0) {
condition.await(); //说明已经有货物啦,当add等待
}
//干活
number++;
System.out.println(Thread.currentThread().getName() + number);
condition.signalAll();
} catch (Exception e) {
lock.unlock();
}
}
public void del() throws InterruptedException {
lock.lock();
try {
while (number == 0) {
condition.await();
}
//干活
number--;
System.out.println(Thread.currentThread().getName() + number);
condition.signalAll();
} catch (Exception e) {
lock.unlock();
}
}
}
public class SpinDemo {
private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
MyData MyData = new MyData();
new Thread(()->{
try {
for (int i = 0; i <5 ; i++) {
MyData.increatement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"AA").start();
new Thread(()->{
try {
for (int i = 0; i <5 ; i++) {
MyData.del();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"BB").start();
}
}
题目七:写一个守护线程的例子
public class ThreadMian {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"====>"+i);
}
});
thread.setDaemon(true);
thread.start();
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (Exception e) {
}
System.out.println("我是主线程");
}
System.out.println("主线程执行完毕!");
}
}
我是主线程
我是主线程
我是主线程
我是主线程
我是主线程
我是主线程
我是主线程
我是主线程
我是主线程
Thread-0====>0
我是主线程
主线程执行完毕!
可以看到主线程结束 守护线程结束
题目八: 指定顺序执行
方法一
/**
* 先执行a 再执行b 再执行c
*/
class Res{
public int count = 1;
public Lock lock = new ReentrantLock();
public Condition c1 = lock.newCondition();
public Condition c2 = lock.newCondition();
public Condition c3 = lock.newCondition();
public void printA() throws InterruptedException {
lock.lock();
if (count!=1){
c1.await();
}
System.out.println(Thread.currentThread().getName());
count=2;
c2.signal();
lock.unlock();
}
public void printB() throws InterruptedException {
lock.lock();
if (count!=2){
c1.await();
}
System.out.println(Thread.currentThread().getName());
count=3;
c2.signal();
lock.unlock();
}
public void printC() throws InterruptedException {
lock.lock();
if (count!=3){
c3.await();
}
**加粗样式** System.out.println(Thread.currentThread().getName());
lock.unlock();
}
}
public class ThreadDemo {
public static void main(String[] args) {
Res res = new Res();
new Thread(()->{
try {
res.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"aa").start();
new Thread(()->{
try {
res.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"bb").start();
new Thread(()->{
try {
res.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"cc").start();
}
}
方法二
class Res{
public void printA() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
}
public void printB() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
}
public void printC() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
}
}
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Res res = new Res();
Thread aa = new Thread(() -> {
try {
res.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "aa");
aa.start();
aa.join();
Thread bb = new Thread(() -> {
try {
res.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "bb");
bb.start();
bb.join();
Thread cc = new Thread(() -> {
try {
res.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "cc");
cc.start();
cc.join();
}
}
题目九: ThreadLocal的使用
class Res {
public int cont = 1;
ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
public int getValue(){
return threadLocal.get();
}
public int addPlus(){ //此时a线程的threadlocal的值已经1,但是他不影响其他的线程,他们仍然从0开始算起
System.out.println(Thread.currentThread().getName()+"====>"+threadLocal.get()+1);
return threadLocal.get()+1;
}
}
public class ThreadMain extends Thread {
public static void main(String[] args) {
Res res = new Res();
new Thread(()->{
int i = res.addPlus();
},"aa").start();
new Thread(()->{
int i = res.addPlus();
},"bb").start();
new Thread(()->{
int i = res.addPlus();
},"cc").start();
}
}
aa====>01
bb====>01
cc====>01
题目十:手敲一个自旋锁/重入锁
public class SpinDemo {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加入刚开始的时候,没有线程进来,此时A进来的时候,刚开始的确为null,此时的确compareAndSet为true ,while返回false
//当B进行修改的时候,发现此时A已经占领了期望值,并不是null ,compareAndSet返回false while返回true.也就是获取不到锁
//当A释放锁的时候,此时他的期望是有当前线程的,thread,改为null,释放锁
//当A释放完后,此时满足了B线程的期望Null 在进入修改.
//同理B释放
public void myLoack () {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"come in ");
while (!atomicReference.compareAndSet(null,thread)){
}
}
public void MyUnlock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
System.out.println(thread.getName()+"come out ");
}
public static void main(String[] args) {
SpinDemo spinDemo = new SpinDemo();
new Thread(()->{
spinDemo.myLoack(); //
try {
Thread.sleep(5000); //确保当a不释放锁的时候,b也进来,获取锁
} catch (InterruptedException e) {
e.printStackTrace();
}
spinDemo.MyUnlock();
},"AA").start();
try {
Thread.sleep(1000); // 确保A先运行
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
spinDemo.myLoack();
spinDemo.MyUnlock();
},"BB").start();
}
}
题目十一:证明递归锁共用一个锁
package 递归锁的验证;
class Res{
public synchronized void SentMessage(){
System.out.println( Thread.currentThread().getName()+"====>"+"发送信息");
sendEmial();
}
public synchronized void sendEmial(){
System.out.println( Thread.currentThread().getName()+"====>"+"发送短信");
}
}
public class ThreadMain {
public static void main(String[] args) {
Res res = new Res();
new Thread(()->{
res.SentMessage();
},"aa").start();
new Thread(()->{
res.SentMessage();
},"bb").start();
}
}
aa====>发送信息 都是aa 说明他们获取是同一把锁
aa====>发送短信
bb====>发送信息
bb====>发送短信
题目十二:如何保证读不受同步控制,写受控制
这里请教大家一个问题,在代码利用读写锁的时候,仍然发现读取的值可能为null, 这主要是a线程和b线程之间的启动时间导致的,确保a线程先启动,加上睡觉即可解决,但是这都是硬代码,我看了一下代码,读写锁也没有实例化condition的方法,各位有什么高见呢?确保一定启动a,然后再启动b
错误代码
/**
这个读写的代码 ,我们题目三已经讲过,但是他有个缺点,就是读取的时候,单线程的而且他并不影响数据的改动,这样很降低效率,读写锁就是读取不加锁,写加锁,更加更好的效率,下面是读写锁的问题: 还没有写入完成 便已经get获取值,他绝对为null
**/
class MyCache{
private volatile Map map = new HashMap();
/**
* 如何确保写的时候不会中断呢?
* @param key
* @param value
* @throws InterruptedException
*/
public void put(String key,Object value) throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"正在写入");
Thread.sleep(300);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完成");
}
/**
* 读取信息
* @param key
* @param integer
* @return
* @throws InterruptedException
*/
public Object get(String key, Integer integer) throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"正在读取");
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完成--->" + o);
return o ;
}
}
public class SpinDemo {
public static void main(String[] args) throws InterruptedException {
MyCache myCache = new MyCache();
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i <5; i++) {
int finalI = i;
executorService.submit(()->{
try {
myCache.put("tempInt"+Integer.valueOf(finalI), Integer.valueOf(finalI));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
for (int i = 0; i <5; i++) {
int finalI = i;
executorService.submit(()->{
try {
myCache.get("tempInt", Integer.valueOf(finalI));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
pool-1-thread-3正在写入
pool-1-thread-4正在写入
pool-1-thread-5正在写入
pool-1-thread-9正在读取
pool-1-thread-9读取完成--->null
pool-1-thread-10正在读取
pool-1-thread-10读取完成--->null
pool-1-thread-1正在写入
pool-1-thread-2正在写入
pool-1-thread-6正在读取
pool-1-thread-6读取完成--->null
pool-1-thread-7正在读取
pool-1-thread-7读取完成--->null
pool-1-thread-8正在读取
pool-1-thread-8读取完成--->null
pool-1-thread-3写入完成
pool-1-thread-4写入完成
pool-1-thread-5写入完成
pool-1-thread-1写入完成
pool-1-thread-2写入完成
改进方案 大佬帮我看看
class Res {
private volatile Map<String, Object> map = new HashMap();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
public void put(String key, Object value) {
try {
lock.writeLock().lock();
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "====>写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public void get(String key) {
try {
lock.readLock().lock();
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "====>读取完成" + o);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
public class ThreadMain {
public static void main(String[] args) throws InterruptedException {
Res res = new Res();
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
res.put("tempInt" + Integer.valueOf(finalI), Integer.valueOf(finalI));
}, "aa").start();
}
// Thread.sleep(3000); 可以解决还未null结果,但是我找不到类似conditon的方法,希望大佬求助
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
res.get("tempInt" + Integer.valueOf(finalI));
}, "bb").start();
}
}
}
aa====>写入完成
aa====>写入完成
aa====>写入完成
aa====>写入完成
aa====>写入完成
bb====>读取完成3
bb====>读取完成2
bb====>读取完成1
bb====>读取完成0
bb====>读取完成4
题目十三:CountDownLatch
public class ThreadMain {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i <10 ; i++) {
int finalI = i;
new Thread(()->{
System.out.println("第"+ finalI +"个学生走啦");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println( Thread.currentThread().getName()+"====>关门啦");
}
}
题目十四:CyclicBarrier
public class ThreadMain {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println(Thread.currentThread().getName() + "====>召唤神龙");
});
for (int i = 1; i <= 7; i++) {
int finalI = i;
new Thread(()->{
System.out.println( Thread.currentThread().getName()+"====>找到了"+ finalI +"龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
1====>找到了1龙珠
7====>找到了7龙珠
3====>找到了3龙珠
2====>找到了2龙珠
4====>找到了4龙珠
5====>找到了5龙珠
6====>找到了6龙珠
6====>召唤神龙 他是最后一个找到的线程召唤的,可不是主线程注意
题目十五:semaphore
public class ThreadMain {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i <6 ; i++) {
new Thread(()->{
try {
semaphore.acquire(); // 我抢到一个车位
System.out.println( Thread.currentThread().getName()+"====>抢到一个车位");
Thread.sleep(3000);
System.out.println( Thread.currentThread().getName()+"====>释放车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();//释放车位
}
},String.valueOf(i)).start();
}
}
}