Day276.Thread和Object类中的重要方法 -Juc
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day276.Thread和Object类中的重要方法 -Juc相关的知识,希望对你有一定的参考价值。
Thread和Object类中的重要方法【二】
一、wait,notify,notifyAll常见面试问题
1、用程序实现两个线程交替打印0-100的奇偶数
- 未优化版本,有许多的废操作,浪费性能
定义两个线程不同的run()方法,一个打印奇数,一个打印偶数;
/******
@author 阿昌
@create 2021-05-23 19:43
*******
* 两个线程交替打印0-100的奇偶数,采用Synchronized实现
*/
public class WaitNotifyPrintOddEvenSyn {
private static int count;
private static final Object lock = new Object();
public static void main(String[] args) {
//处理【偶数】线程
Thread even = new Thread(new Runnable() {
@Override
public void run() {
while (count < 100) {
synchronized (lock) {
if ((count & 1) == 0) {
System.out.println(Thread.currentThread().getName()+","+count);
count++;
}
}
}
}
});
//处理【奇数】线程
Thread odd = new Thread(new Runnable() {
@Override
public void run() {
while (count < 100) {
synchronized (lock) {
if ((count & 1) == 1) {
System.out.println(Thread.currentThread().getName()+","+count);
count++;
}
}
}
}
});
even.start();
odd.start();
}
}
- 结果
- 优化版本,使用wait、notify
通过只写一个Runnable实现,来让现场交替打印奇偶数
/******
@author 阿昌
@create 2021-05-23 20:05
*******
* 两个线程交替打印 0 - 100 的奇偶数,用wait和notify
*/
public class WaitNotifyPrintOddEven {
private static int count = 0;
private static final Object lock = new Object();
//主函数
public static void main(String[] args) {
TurningRounder turningRounder = new TurningRounder();
Thread even = new Thread(turningRounder);
Thread odd = new Thread(turningRounder);
even.start();
odd.start();
}
static class TurningRounder implements Runnable {
@Override
public void run() {
while (count <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + "," + count++);
lock.notify();
if (count <= 100) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
- 结果
2、手写生产者消费者设计模式
/******
@author 阿昌
@create 2021-05-22 20:58
*******
* 用wait/notify来实现 生产者消费者模式
*/
public class ProducerConsumerModel {
//主函数
public static void main(String[] args) {
EventStorage eventStorage = new EventStorage();
Consumer1 consumer = new Consumer1(eventStorage);
Producer1 producer = new Producer1(eventStorage);
Thread threadConsumer = new Thread(consumer);
Thread threadProducer = new Thread(producer);
threadConsumer.start();
threadProducer.start();
}
}
//生产者
class Producer1 implements Runnable{
private EventStorage storage;
public Producer1(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
//消费者
class Consumer1 implements Runnable{
private EventStorage storage;
public Consumer1(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
//队列
class EventStorage{
private int maxSize;
private LinkedList storage;
public EventStorage(){
this.maxSize=10;
storage = new LinkedList<>();
}
//生成产品
public synchronized void put(){
//如果满了
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没满
storage.add(new Date());
System.out.println("生产者生产了产品,仓库里有了"+storage.size()+"个产品");
notify();
}
//消费产品
public synchronized void take(){
//如果空了
while (storage.size()<=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没空
System.out.println("消费者消费了产品,拿到了"+storage.poll()+",现在仓库还剩下"+storage.size());
notify();
}
}
3、为什么wait()需要在同步代码块内使用,而sleep()不需要
为了线程通信可靠,防止死锁发生
4、为什么线程通信的方法wait,notify和notifyAll被定义在Object类里,而sleep定义在Thread类里?
因为wait,notify和notifyAll是锁级别的操作
;
锁是属于某一个对象的,每一个对象的对象头中含有即为来保留当前锁状态,锁是绑定到某个对象中,而不是线程中
5、wait方法是属于Object对象,那么调用Thread.wait()会怎么样?
首先Thread也是一个对象,他也继承于Object类,但是对于Thread类比较特殊,他在执行完会自动执行notify()方法,这样子可能会使设计的流程受到干扰,所以他Thread类本身不适合做锁对象
6、如何选择用notify和nofityAll
考虑是要唤醒一个线程还是多个线程
7、notifyAll之后所有的线程都会再次抢夺锁,如果某线程抢夺失败怎么办?
他们会陷入到一个等待阻塞的状态,等待那个锁被释放,再去抢夺那把锁
8、用suspend()和resume()来阻塞线程可以吗?为什么?
已经因为线程安全问题被弃用
了,推荐使用wait和notify
二、Java相关概念
1、JavaSE、JavaEE、JavaME是什么?
- JavaSE:标准版
- JavaEE:企业版
- JavaME:移动版
2、JRE和JDK和JVM是什么关系?
- JRE:Java运行环境(包含JVM)
- JDK:Java开发工具包,用于开发(JDK包含JRE)
- JVM:Java虚拟机,Java运行的必要东西
3、Java版本升级都包括了哪些东西的升级?
Java类升级、JVM升级
4、Java8和Java1.8和JDK8是什么关系,是同一个东西吗?
JavaSE8 ==Java8 == Java1.8 == JDK8
三、Sleep()方法详解
1、作用
2、sleep()方法不释放锁
- 不释放synchronized
/******
@author 阿昌
@create 2021-05-23 21:05
*******
* 展示线程sleep的时候不释放sychronized的monitor,等sleep时间到了后,
* 正常结束后才会释放锁
*/
public class SleepDontReleaseMonitor implements Runnable {
//主函数
public static void main(String[] args) {
SleepDontReleaseMonitor s = new SleepDontReleaseMonitor();
Thread thread1 = new Thread(s);
Thread thread2 = new Thread(s);
thread1.start();
thread2.start();
}
@Override
public void run() {
syn();
}
private synchronized void syn(){
System.out.println("线程:"+Thread.currentThread().getName()+"获取到了monitor。");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread().getName()+"退出同步代码块");
}
}
- 不释放lock
/******
@author 阿昌
@create 2021-05-23 21:13
*******
* sleep不是释放lock(lock需要手动释放)
*/
public class SleepDontReleaseLock implements Runnable {
private static final Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();
System.out.println("线程:"+Thread.currentThread().getName()+"获取到了锁");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
//主函数
public static void main(String[] args) {
SleepDontReleaseLock s = new SleepDontReleaseLock();
Thread thread1 = new Thread(s);
Thread thread2 = new Thread(s);
thread1.start();
thread2.start();
}
}
- 和wait()不同,wait()会释放锁,sleep()不会
3、sleep方法响应中断
- 抛出InterruptedException
/******
@author 阿昌
@create 2021-05-23 21:22
*******
* 每隔一秒钟输出当前时间,但是中途被中断,观察
* 两种写法:1、Thread.sleep()
* 2、TimeUnit.SECONDS.sleep()
*/
public class SleepInterrupted implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("我被中断了");
e.printStackTrace();
}
}
}
//主函数
public static void main(String[] args) throws InterruptedException {
SleepInterrupted sleepInterrupted = new SleepInterrupted();
Thread thread = new Thread(sleepInterrupted);
thread.start();
Thread.sleep(5000);
//中断
thread.interrupt();
}
}
4、总结
5、sleep常见面试题
wait/notify、sleep的异同(方法属于哪个对象?线程状态怎么切换?)
- 相同点:
- 阻塞
- 可以响应interrupted中断
- 不同点:
wait/notify
- 使用在同步方法中
- 释放锁
- 可选指定时间
- 属于Object类
sleep
- 可不使用在同步方法中
- 不释放锁
- 可指定时间
- 属于Thread类
四、Join()方法详解
1、作用、用法
作用:因为新的线程加入了我们,所有我们需要等待他们执行完成再出发
用法:主线程等待子线程执行完毕,注意谁等谁
2、代码演示
/******
@author 阿昌
@create 2021-05-23 21:44
*******
* 演示Join用法,注意语句的输出顺序,会变化。
*/
public class Join {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程执行完毕");
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":线程执行完毕");
}
});
thread1.start();
thread2.start();
System.out.println("开始等待子线程运行完毕");
thread1.join();
thread2.join();
System.out.println("所有子线程执行完毕");
}
}
- 结果
两个子线程都睡1s,所以主线程先打印出开始等待子线程运行完毕
然后在执行子线程
- 如果注掉
thread1.start();
thread2.start();
System.out.println("开始等待子线程运行完毕");
// thread1.join();
// thread2.join();
System.out.println("所有子线程执行完毕");
- 结果
主线程直接在1s内执行完开始等待子线程运行完毕
、所有子线程执行完毕
语句
然后子线程才执行完
3、join遇到中断
/******
@author 阿昌
@create 2021-05-23 21:56
*******
* Join的中断演示
*/
public class JoinInterrupted {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//中断主线程
mainThread.interrupt();
Thread.sleep(5000);
System.out.println("Thread1 执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程运行完毕");
}
});
thread1.start();
System.out.println("等待子线程运行完毕");
try {
thread1.join();
} catch (InterruptedException e) {
System.out.以上是关于Day276.Thread和Object类中的重要方法 -Juc的主要内容,如果未能解决你的问题,请参考以下文章
5.线程的八大核心基础知识之Thread和Object类中的重要方法详解
JAVA零基础小白学习教程之day10-API&Object&String