今日内容
零、 复习昨日
一、作业
售卖后车票
见代码
二、线程安全的类[了解]
三、死锁[了解]
public class MyLock {
// 左筷子锁
static Object zuo = new Object();
// 右筷子锁
static Object you = new Object();
}
public class Girl extends Thread{
@Override
public void run() {
synchronized (MyLock.zuo) {
System.out.println("女朋友获得左筷子" );
synchronized (MyLock.you) {
System.out.println("女朋友获得右筷子-吃饭" );
}
}
}
}
public class Boy extends Thread{
@Override
public void run() {
synchronized (MyLock.you) {
System.out.println("男朋友获得右筷子" );
synchronized (MyLock.zuo) {
System.out.println("男朋友获得右左筷子-吃饭" );
}
}
}
}
public class TestDeadLock {
public static void main(String[] args) {
new Boy().start();
new Girl().start();
}
}
四、线程通信[熟悉]
4.1 介绍
4.2 两个个线程通信
需求: 昨天打印机方法,让print1()和print2()方法交替执行
package com.qf.notify;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 通信
*/
public class Printer {
/**
* 打印机执行的标志
* 此标志如果是1,说明该打印机1执行,否则打印机1停下
* 此标志如果是2,说明该打印机2执行,否则打印机2停下
*/
private int flag = 1;
public synchronized void print1() throws InterruptedException {
if (flag != 1) { // 判断不是自己执行时
// 线程停下不执行
// 锁对象是谁,谁去wait方法
this.wait();
}
System.out.print("1 " );
System.out.print("2 " );
System.out.print("3 " );
System.out.print("4 " );
System.out.print("\r\n" );
// 改变标志
flag = 2;
// 通知其他处于等待状态的线程,起来干活
// 锁对象是谁,谁去notify方法
this.notify();
}
public synchronized void print2() throws InterruptedException {
if ( flag != 2) {
this.wait();
}
System.out.print("A " );
System.out.print("B " );
System.out.print("C " );
System.out.print("D " );
System.out.print("\r\n" );
flag = 1;
this.notify();
}
}
public class TestNotify {
public static void main(String[] args) {
Printer printer = new Printer( );
new Thread(){
@Override
public void run() {
while(true){
try {
printer.print1();
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while(true){
try {
printer.print2();
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
}
}.start();
}
}
package com.qf.notify;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 通信
*/
public class Printer2 {
Object obj = new Object();
private int flag = 1;
public void print1() throws InterruptedException {
synchronized (obj) {
if (flag != 1) { // 判断不是自己执行时
// 线程停下不执行
// 锁对象是谁,谁去wait方法
obj.wait( );
}
System.out.print("1 ");
System.out.print("2 ");
System.out.print("3 ");
System.out.print("4 ");
System.out.print("\r\n");
// 改变标志
flag = 2;
// 通知其他处于等待状态的线程,起来干活
// 锁对象是谁,谁去notify方法
obj.notify( );
}
}
public void print2() throws InterruptedException {
synchronized (obj) {
if (flag != 2) {
obj.wait( );
}
System.out.print("A ");
System.out.print("B ");
System.out.print("C ");
System.out.print("D ");
System.out.print("\r\n");
flag = 1;
obj.notify( );
}
}
}
4.3 练习
创建A1 A2 两个线程,分别打印1-10,11-20,保证A1执行完再 执行A2线程,A2执行完再执行A1
A1 —> 1
A2 —>11
A1 —> 2
A2 —>12
package com.qf.notify;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class TestA1A2 {
static int flag = 1;
public static void main(String[] args) {
Object o = new Object( );
new Thread( ) {
@Override
public void run() {
for (int i = 1; i < 11; i++) {
synchronized (o) {
if (flag != 1) {
try {
o.wait( );
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
System.out.println("A1 -->" + i);
flag = 2;
o.notify( );
}
}
}
}.start( );
new Thread( ) {
@Override
public void run() {
for (int i = 11; i < 21; i++) {
synchronized (o) {
if (flag != 2) {
try {
o.wait( );
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
System.out.println("A2 -->" + i);
flag = 1;
o.notify( );
}
}
}
}.start( );
}
}
4.4 三个线程的通信
如果是notify
解决方案: 全部唤醒 ,使用方法notifyAll(),唤醒所有处于等待状态的线程
package com.qf.notify;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class Printer {
int flag = 1;
public synchronized void print1() throws Exception{
while (flag != 1) {
this.wait();// 哪里等待,被唤醒后继续执行,
// 将此处的if改成while,目的是让线程唤醒后继续回头再判断一次
}
System.out.print("1 ");
System.out.print("2 ");
System.out.print("3 ");
System.out.print("4 ");
System.out.print("\r\n");
flag = 2;
//this.notify();// 随机唤醒处于等待状态的一条线程
this.notifyAll();// 唤醒全部处于等待状态的线程
}
public synchronized void print2() throws Exception{
while (flag != 2) {
this.wait();
}
System.out.print("A ");
System.out.print("B ");
System.out.print("C ");
System.out.print("D ");
System.out.print("\r\n");
flag = 3;
this.notifyAll();
}
public synchronized void print3() throws Exception{
while (flag != 3) {
this.wait();
}
System.out.print("一 ");
System.out.print("二 ");
System.out.print("三 ");
System.out.print("四 ");
System.out.print("\r\n");
flag = 1;
this.notifyAll();
}
}
4.5 总结
五、生产者消费者
package com.qf.pc;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 商品
*/
public class Phone {
private String desc;
public Phone(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Phone{" +
"desc='" + desc + '\'' +
'}';
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.qf.pc;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class Shop {
private Phone phone;
// 进货(生产)
public synchronized void product(Phone phone) {
if (this.phone != null) {// 如果商店还有手机,暂时等待消费先不生产
try {
//System.out.println("商店有手机,请来消费" );
this.wait();
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
// 如果商店没手机,就生产
this.phone = phone;
System.out.println("生产中...." );
// 通知消费
this.notify();
}
// 消费
public synchronized void consumer() {
if (this.phone == null) {// 商店没有手机,等待生产
try {
//System.out.println("商店没有手机,请赶紧生产...");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
// 消费完,手机就没啦
this.phone = null;
System.out.println("消费中..." );
// 通知生产
this.notify();
}
public static void main(String[] args) {
Shop shop = new Shop( );
new Thread(){ // 一个线程生产
@Override
public void run() {
for (int i = 1; i < 10; i++) {
shop.product(new Phone("XIAOMI"+i));
}
}
}.start();
new Thread(){ // 一个线程消费
@Override
public void run() {
for (;;) {
shop.consumer();
}
}
}.start();
}
}
六、线程池
6.1 线程池概念
6.2 线程池原理
6.3 创建线程池的方式
使用线程池创建线程,执行任务
6.4 不同特点的线程池
线程池执行任务时,可以采用两种方法:
package com.qf.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class TestThreadPool {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor( );
for (int i = 0; i < 10; i++) {
threadPool.execute(new Runnable( ) {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务" );
}
});
}
threadPool.shutdown();
}
private static void show3() {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);
// execute这样没有定时执行
// threadPool.execute(new Runnable( ) {
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName()+"执行任务" );
// }
// });
/**
* schedule(Runnable r,long delay,TimeUnit 单位)
*/
for (int i = 0; i < 3; i++) {
threadPool.schedule(new Runnable( ) {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务" );
}
},3, TimeUnit.SECONDS);
}
threadPool.shutdown();
}
private static void show2() {
// 创建缓冲线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool( );
for (int i = 0; i < 5000; i++) {
cachedThreadPool.execute(new Runnable( ) {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务..." );
}
});
}
cachedThreadPool.shutdown();
}
/**
* 固定大小线程池
*/
private static void show1() {
// 使用工具类来创建不同类型的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
// 执行任务
// void execute()
// Future submit()
for (int i = 1; i < 41; i++) {
fixedThreadPool.execute(new Runnable( ) {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"在执行..." );
}
});
}
// 线程池关闭
fixedThreadPool.shutdown();
}
}
6.5 ThreadPoolExecutor[重要]
问: 什么是创建临时线程?
答: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建线程
问:什么时候开始拒绝任务?
答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来就会拒绝
public static void main(String[] args) {
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
// new ThreadPoolExecutor(
// 5,// 核心线程数
// 15,// 最大线程数
// 1, // 存活时间
// TimeUnit.MINUTES,
// queue,// 任务队列
// Executors.defaultThreadFactory(),// 默认的工厂
// new ThreadPoolExecutor.AbortPolicy());// 拒绝策略
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,// 核心线程数
15,// 最大线程数
1, // 存活时间
TimeUnit.MINUTES,
queue// 任务队列
);
for (int i = 0; i < 45; i++) {
threadPoolExecutor.execute(new Runnable( ) {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行..." );
}
});
}
System.out.println(queue );
System.out.println(queue.size() );
}