一、死锁
开发中不用死锁,面试会问:
应用场景:并发场景,多线程,线程之间互不相让,得借助于锁
加锁得目的是为了线程安全,物极必反,尤其是加了锁以后
死锁是一个状态,当两个线程互相持有对方想要得资源得时候,却又不主动释放这个资源得时候,会导致死锁,到家都用不了线程,就无法执行下去。
线程1有一个锁1
线程2有个锁2
线程1等待锁2得释放
线程2等待锁1得释放
死锁案例:背会,面试需手写
package com.qfedu.test;//死锁class DeadLock implements Runnable{private boolean isFlag;private Object obj1;private Object obj2;public DeadLock(boolean isFlag, Object obj1, Object obj2) {this.isFlag = isFlag;this.obj1 = obj1;this.obj2 = obj2;}@Overridepublic void run() {if(isFlag) {//如果是true让线程1进来synchronized (obj1) {//锁得是obj1对象//线程1System.out.println(Thread.currentThread().getName() + "锁1");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("等待锁2得释放");synchronized (obj2) {System.out.println(Thread.currentThread().getName() + "拿到锁2");}}}if (!isFlag) {//如果为false,让线程2进来synchronized(obj2) {System.out.println(Thread.currentThread().getName() + "锁2");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("等待锁1得释放");synchronized (obj1) {System.out.println(Thread.currentThread().getName() + "拿到锁1");}}}}}public class Demo1 {public static void main(String[] args) {Object object1 = new Object();Object object2 = new Object();//第一个线程执行锁1new Thread(new DeadLock(true, object1, object2),"线程1").start();//第二个线程执行锁2new Thread(new DeadLock(false, object1, object2),"线程2").start();}}
二、线程的生命周期
1.线程的创建,开启线程
2.可运行状态,CPU等待,CPU抢占
3.运行状态,CPU使用,CPU等待,CPU抢占
4.阻塞状态,锁,sleep,wait
5.消亡
三、和线程相关的重要方法
object类下面的方法
public final void wait() throws InterruptedException
导致线程等待,知道另一个线程调用该对象的notify()或notifyAll()方法。
总结:对象来调用wait方法,在一个线程中 对象.wait() 这个线程会阻塞。
想让这个线程继续执行,需要使用另外一个线程去拿同一个对象调用notify方法去唤醒线程
注意事项:
1.功能是线程等待(阻塞状态),2.需要使用对象调用3.wait方法一般搭配锁一起使用(保证是同一个对象锁)
package com.qfedu.test2wait;//wait//对象调用wait方法,得有对象,有对象得先有类class Message{private String message;public Message() {}public Message(String message) {this.message = message;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}@Overridepublic String toString() {return "Message [message=" + message + "]";}}//线程 作为等待线程class Waiter implements Runnable{//Waiter 是一个类 可以写构造方法private Message msg;//一个类下面得属性可以是另外一个类对象//因为要使用对象.wait方法public Waiter(Message msg) {this.msg = msg;}@Overridepublic void run() {String name = Thread.currentThread().getName();synchronized (msg) {System.out.println(name + "等待唤醒时间:" + System.currentTimeMillis());try {msg.wait();//走到这一步 线程不会往下走了} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("线程wait了");System.out.println(name + "被唤醒时间:" + System.currentTimeMillis());System.out.println(name + "#线程#" + msg.getMessage());}}}//唤醒线程class Notifier implements Runnable{private Message msg;public Notifier(Message msg) {super();this.msg = msg;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "开始唤醒等待线程");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (msg) {msg.setMessage("!!!!我是修改之后的Message属性值");//开始唤醒 msg是等待线程和唤醒线程中的同一个对象msg.notify();msg.notify();msg.notify();// msg.notifyAll();System.out.println("hahaha?");}}}public class Demo1 {public static void main(String[] args) {Message message = new Message("我是Message属性");Waiter waiter = new Waiter(message);new Thread(waiter,"等待线程1").start();new Thread(waiter,"等待线程2").start();new Thread(waiter,"等待线程3").start();Notifier notifier = new Notifier(message);new Thread(notifier,"唤醒线程").start();}}
四、生产者消费者模式【重要】
和上午wait和notify方法有关
package com.qfedu.test3Anili;//生产者消费者模式 案例 购车//这个类作为线程之间共享的一个资源,会当成一个锁对象class Goods {private String name;// 商品名字private double price;// 商品价格private boolean isProduct;// 商品是否需要生产public Goods() {}public Goods(String name, double price, boolean isProduct) {this.name = name;this.price = price;this.isProduct = isProduct;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public boolean isProduct() {return isProduct;}public void setProduct(boolean isProduct) {this.isProduct = isProduct;}@Overridepublic String toString() {return "Goods [name=" + name + ", price=" + price + ", isProduct=" + isProduct + "]";}}//生产者class Producer implements Runnable {private Goods goods;public Producer(Goods goods) {this.goods = goods;}@Overridepublic void run() {int count = 0;while (true) {synchronized (goods) {if (goods.isProduct()) {// true 需要生成if (count % 2 == 0) {// 偶数生成汉goods.setName("比亚迪汉");goods.setPrice(30);} else {// 奇数生产唐goods.setName("比亚迪唐");goods.setPrice(25);}// 生产完以后就不需要生产了 改为falsegoods.setProduct(false);System.out.println("生产者生产了:" + goods.getName() + ",价格为:" + goods.getPrice());count++;// 生产好了 唤醒消费者goods.notify();} else {System.out.println("3");// 不需要生产 生产者进入等待状态(阻塞)try {goods.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("4");}}}}}//消费者class Consumer implements Runnable {private Goods goods;public Consumer(Goods goods) {this.goods = goods;}@Overridepublic void run() {while (true) {// System.out.println("睡一会儿再买");try {Thread.sleep(1000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}synchronized (goods) {// 如果是true 需要生成 就是没商品if (!goods.isProduct()) {// false// 不需要生成System.out.println("消费者购买了:" + goods.getName() + ":价格为" + goods.getPrice());// 购买完商品就没了goods.setProduct(true);// 唤醒生产者去生产goods.notify();} else {System.out.println("1");// 需要生成 消费者进入阻塞状态try {goods.wait();continue;} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("2");}}}}}public class Demo1 {public static void main(String[] args) {Goods goods = new Goods("比亚迪汉!!!", 178, false);Consumer consumer = new Consumer(goods);new Thread(consumer, "消费者线程").start();Producer producer = new Producer(goods);new Thread(producer, "生产者线程").start();}}
匿名内部类写法【简写】
package com.qfedu.test4;//创建线程的第三种方式public class Demo1 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(i);}}});thread.start();new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(i);}}}).start();}}
五、创建线程的第三种方式
1.创建Callable接口的实现类,并实现call方法,该call方法有返回值,在去创建Callable的实现类对象
2.使用一个类 FutureTask这个类去包装Callable 对象,FutureTask对象变相的封装了call方法
3.使用Futruetask对象作为Thread对象的参数并启动新线程
4.可以使用FutureTask.get()这个的对象获取子线程执行结束返回值
package com.qfedu.test4;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {// TODO Auto-generated method stubfor (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "啥啊");}return "aaaa";}}public class Demo2 {private static final int String = 0;public static void main(String[] args) throws InterruptedException, ExecutionException {MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();FutureTask<String> task1 = new FutureTask<String>(myThread1);FutureTask<String> task2 = new FutureTask<String>(myThread2);new Thread(task1,"线程1").start();new Thread(task2,"线程2").start();System.out.println(task1.get());}}
