线程的定义
-
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个主线程。
-
系统资源分配给进程,同一进程的所有线程共享该进程的所有资源。
-
线程是指进程内的一个执行单元,也是进程内的可调度实体。
多线程的定义
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
也就是说允许单个程序创建多个并行执行的线程来完成各自的任务
多线程的示例图
一个线程的生命周期
多线程的优点
- Java支持编写多线程的程序;
- 多线程最大好处在于可以同时并发执行多个任务;
- 多线程可以最大限度地减低CPU的闲置时间,从而提高CPU的利用率
多线程的缺点
- 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
- 多线程需要协调和管理,所以需要CPU时间跟踪线程;
- 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
- 线程太多会导致控制太复杂,最终可能造成很多Bug。
线程的三种创建方法
1.继承Thread
// 继承 Thread 类 创建一个线程
class Thread_01 extends Thread {
private Thread t;
private String t_name;
public Thread_01( String name ) {
t_name = name;
System.out.println("创建线程:" + t_name );
}
@Override
public void run() {
System.out.println(" 开始运行:" + t_name );
try {
for ( int i = 5; i > 0; i-- ) {
System.out.println(" 线程 " + t_name + "---" + i );
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 运行结束:" + t_name );
}
//封装下start()方法,不封装也可以直接调用
public void start_Thread_01() {
System.out.println(" 开始一个线程:" + t_name );
if ( t == null ) {
t = new Thread(this, t_name);
t.start();
}
}
}
public class Code_002 {
public static void main(String[] args) {
Thread_01 r1 = new Thread_01(" No.1 ");
r1.start_Thread_01();
Thread_01 r2 = new Thread_01(" No.2 ");
r2.start_Thread_01();
}
}
2.实现Runnable接口
// 实现 Runnalbe 接口 创建线程
class Runnable_01 implements Runnable {
private Thread t;
private String t_name;
public Runnable_01( String name ) {
t_name = name;
System.out.println(" 创建线程:" + t_name );
}
@Override
public void run() {
System.out.println(" 开始运行:" + t_name );
try {
for ( int i = 5; i > 0; i-- ) {
System.out.println(" 线程 " + t_name + "---" + i );
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 运行结束:" + t_name );
}
// public void start() {
public void start_Runnable_01() {
System.out.println(" 开始一个线程:" + t_name );
if ( t == null ) {
t = new Thread(this, t_name);
t.start();
}
}
}
public class Code_001 {
public static void main(String[] args) {
Runnable_01 r1 = new Runnable_01(" No.1 ");
r1.start_Runnable_01();
Runnable_01 r2 = new Runnable_01(" No.2 ");
r2.start_Runnable_01();
}
}
3. Callable + Future 接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 实现 Callable + Future 接口 创建一个线程
class Callable_01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int i = 0;
while ( i < 7 ) {
System.out.println( Thread.currentThread().getName() + ": " + i );
i++;
}
return i;
}
}
public class Code_003 {
public static void main(String[] args) {
Callable_01 c1 = new Callable_01();
FutureTask<Integer> f1 = new FutureTask<Integer>(c1);
for ( int i = 0; i < 10; i++ ) {
System.out.println( Thread.currentThread().getName() + ": " + i );
if ( i == 7 ) {
new Thread(f1, "有返回值的线程——call()").start();
}
}
try {
System.out.println(" 有返回值的线程返回的数值:" + f1.get() );
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用匿名的内部类创建进程
使用 Thread 实现匿名内部类和 Runnable 实现匿名接口
// 匿名内部类
Thread t1=new Thread() {
public void run() {
int i;
for (i = 15; i >0; i--) {
System.out.println("小明正在修改策划,需要"+i+"秒");
try {
Thread.sleep(1000);//sleep函数睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i==0) {
System.out.println("小明修改策划成功!!!");
}
}
};
t1.start();
// 匿名内部类 ,匿名对象
new Thread(
new Runnable(){
int m=11119999;
public void run(){
System.out.println("匿名内部类,匿名对象,m="+m);
}
}
).start();
创建线程的三种方式的对比
-
采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
-
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程
Thread类中的常用方法:
下面给出两个示例
//两个线程分别打印奇偶交替输出
public class PrinterRunnable implements Runnable {
private int x=100;
@Override
public void run() {
for(int i=0;i<100&&x>1;){
synchronized(this) {
if(Thread.currentThread().getName().equals("线程1")&&x%2!=0) {
System.out.println(Thread.currentThread().getName()+" x="+x);
x--;
i++;
}
if(Thread.currentThread().getName().equals("线程2")&&x%2==0) {
System.out.println(Thread.currentThread().getName()+" x="+x);
x--;
i++;
}
};
}
}
public static void main(String[] args) {
PrinterRunnable pr1=new PrinterRunnable();
Thread t1=new Thread(pr1,"线程1");
Thread t2=new Thread(pr1,"线程2");
t1.start();
t2.start();
}
}
在终端的结果
下个例子涉及到join()、sleep()
public class JoinTest implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("小华正在打LOL");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {//
JoinTest j1=new JoinTest();
Thread t3=new Thread(j1,"线程1");
// 匿名内部类创建线程
Thread t4=new Thread() {
public void run() {
int i;
for (i = 15; i >0; i--) {
System.out.println("小明正在赶策划,需要"+i+"秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i==0) {
System.out.println("小明赶策划成功!!!");
}
}
};
t4.start();
try {
t4.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t3.start();
}
}
在终端的显示
同步(synchronized)
一个线程访问同步方法(代码块)
class Test {
// 同步代码块
public void fun_01() {
synchronized (this) {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " 同步方法_01 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 非同步代码块
public void fun_02() {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " 非同步方法 _02 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 同步代码块
public void fun_03() {
synchronized (this) {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " 同步方法_03 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 同步方法
public synchronized void fun_syn() {
}
}
public class Code_001 {
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(
new Runnable() {
@Override
public void run() {
test.fun_01();
}
}, " 线程-t1 "
);
Thread t2 = new Thread(
new Runnable() {
@Override
public void run() {
test.fun_03();
}
}, " 线程-t2 "
);
t1.start();
t2.start();
/*
* 基本原则:
*
* 1. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个同步方法(代码块)的访问将被阻塞
*
* 2. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个非同步方法(代码块)的访问仍然可以
*
* 3. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个其他同步方法(代码块)的访问将被阻塞
*
*
*/
}
}
第三种情况的运行情况如下
对象锁(实例锁),全局锁
/*
* 类内的方法,均为——同步方法
*
*/
class Test_01 {
// 实例方法
public synchronized void fun_01() {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " fun_01 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 实例方法
public synchronized void fun_02() {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " fun_02 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 静态方法(类方法)
public static synchronized void fun_03() {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " static_fun_03 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 静态方法(类方法)
public static synchronized void fun_04() {
try {
for ( int i = 0; i < 5; i++ ) {
Thread.sleep(200);
System.out.println( Thread.currentThread().getName() + " - " + " static_fun_04 " + i );
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Code_002 {
public static void main(String[] args) {
Test_01 tA = new Test_01();
Test_01 tB = new Test_01();
/*
* 实例锁 —— 对象锁
*
* 锁的是同一个对象 tA,虽然调用的是不同的 同步方法 01 和 02
*
* 但依然会进行同步执行(原因基本规则三)
*
*/
// Thread t1 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
// tA.fun_01();
// }
// }, " 线程-t1 "
// );
//
// Thread t2 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
// tA.fun_02();
// }
// }, " 线程-t2 "
// );
//
// t1.start();
// t2.start();
/*
* 实例锁 —— 对象锁
*
* 锁的是两个对象 tA、tB,虽然调用的是相同的 同步方法 01
*
* 但不会进行同步执行(原因基本规则一)
*
*/
// Thread t1 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
// tA.fun_01();
// }
// }, " 线程-t1 "
// );
//
// Thread t2 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
// tB.fun_01();
// }
// }, " 线程-t2 "
// );
//
// t1.start();
// t2.start();
/*
* 全局锁 —— 类型锁
*
* 锁的是一整个类型,所有的对象 共用一个静态方法(类方法)
* 进一步推断,所有对象调用 同步方法03 或 04 时,在使用类里面的同一把锁
*
* 但依然会进行同步执行(原因基本规则一)
*/
// Thread t1 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
// tA.fun_03();
// Test_01.fun_03();
// }
// }, " 线程-t1 "
// );
//
// Thread t2 = new Thread(
//
// new Runnable() {
//
// @Override
// public void run() {
//
tB.fun_03();
// tA.fun_04();
Test_01.fun_04();
Test_01.fun_03();
// }
// }, " 线程-t2 "
// );
//
// t1.start();
// t2.start();
/*
* 实例锁 —— 对象锁
* 全局锁 —— 类型锁
*
* 线程1 持有对象tA的实例锁,线程2 持有类型Test_01的全局锁,
* 两个线程分别使用两把不一样的锁
*
* 因此,不会进行同步执行
*
*/
Thread t1 = new Thread(
new Runnable() {
@Override
public void run() {
tA.fun_01();
}
}, " 线程-t1 "
);
Thread t2 = new Thread(
new Runnable() {
@Override
public void run() {
Test_01.fun_03();
}
}, " 线程-t2 "
);
t1.start();
t2.start();
}
}
分别调用对象锁和全局锁的结果
同步锁中wait()和notify()的使用
下面有两种情况情况一是,不管有没有notify都会自己解锁,情况2是必须等待唤醒才能解锁,具体的分析在代码里
情况1
class Thread_03 extends Thread {
public Thread_03( String name ){
super(name);
}
@Override
public void run() {
synchronized (this) {
System.out.println( Thread.currentThread().getName() + " 开始执行! ");
System.out.println( Thread.currentThread().getName() + " 进行唤醒!");
//notify();
/*
* 此处 无论有没有 notify() 方法,外面的主线程依然会正常执行结束
*
* 分析原因:
* 1. test线程执行完 run() 之后,test线程正常结束。
* 2. 那么执行 “ test.wait() ”这句代码的线程(main线程)退出等待队列,相当于唤醒。
* 3. 然后 main线程获取同步锁,进入就绪进而执行
*
*
* 核心关键点:
*
* 当“某线程”正常结束之后,会使以“这个线程作为对象”运行的wait()的线程(main线程)等待状态结束。
*
*
* test.wait() 在代码中的实际作用:
*
* 在当前线程(main线程)中,以 test线程作为对象,调用wait()方法
*/
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println( Thread.currentThread().getName() + " 执行结束! ");
}
}
}
public class Code_003 {
public static void main(String[] args) {
Thread_03 test = new Thread_03(" 线程 test ");
synchronized ( test ) {
try {
System.out.println( Thread.currentThread().getName() + " 启动 【线程 test】");
test.start();
System.out.println( Thread.currentThread().getName() + " 即将进行 wait() ");
test.wait(); // 是 main线程在执行 这行代码,因此 main线程进入等待状态
System.out.println( Thread.currentThread().getName() + " wait() 执行完毕 ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
情况二
class Thread_04 extends Thread {
public Thread_04( String name ) {
super(name);
}
@Override
public void run() {
synchronized ( Code_004.lockstr ) {
System.out.println( Thread.currentThread().getName() + " 开始执行! ");
System.out.println( Thread.currentThread().getName() + " 进行唤醒!");
// Code_004.lockstr.notify();
/*
* 如果这里没有唤醒方法,则test线程执行结束之后,
* 调用“ Code_004.lockstr.wait(); ”代码的线程(main线程)无法被唤醒,那么程序就一直卡在这
*
*
* 核心关键点:
*
* Code_004.lockstr是一个对象,但不是一个线程作为对象!
*
*
* Code_004.lockstr.wait() 在代码中的实际作用:
*
* 在当前线程(main线程)中,以Code_004.lockstr对象,调用wait()方法
*/
try {
sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println( Thread.currentThread().getName() + " 执行结束! ");
}
}
}
public class Code_004 {
public static String lockstr = "lock";
public static void main(String[] args) {
Thread_04 test = new Thread_04(" 线程 test ");
synchronized ( Code_004.lockstr ) {
try {
System.out.println( Thread.currentThread().getName() + " 启动 【线程 test】");
test.start();
System.out.println( Thread.currentThread().getName() + " 即将进行 wait() ");
Code_004.lockstr.wait(); // 是 main线程在执行 这行代码,因此 main线程进入等待状态
System.out.println( Thread.currentThread().getName() + " wait() 执行完毕 ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
生产着和消费者模型
// 仓库
class Depot {
private int capacity; // 容量
private int size; // 实际存放的数量
public Depot( int num ) {
this.capacity = num;
this.size = 0;
}
// 生产行为
public synchronized void produce( int num ) throws InterruptedException {
// num 表示需要生产的数量,这个数量有可能比实际剩余的容量多
// left 表示即将被生产的数量,这个数量有可能比实际剩余的容量多
int left = num;
while ( left > 0 ) {
// 当仓库满了,则需要等待 “消费者” 从仓库 消费 商品(为了腾出位置放新的商品)
while ( size >= capacity ) {
wait();
}
// “实际生产的数量” —— 实际存放到仓库里面的商品数量
int actual_produce = 0;
/*
* 如果 库存+想要生产的数量 大于 总容量,
* 则 实际生产的数量 = 总容量 - 库存
* 否则 实际生产的数量 = 想要生产的数量
*/
actual_produce = ((size + left) > capacity) ? (capacity-size) : left;
// 放入仓库,size 增加 actual
size += actual_produce;
// 即将放入的数量会随着放入仓库成功的行为而减少
left -= actual_produce;
System.out.println(Thread.currentThread().getName() + " 需要生产:" + num +
" 实际放到仓库:" + actual_produce +
" 仓库现有库存:" + size +
" 还需要生产:" + left );
// 唤醒 消费者 进行 商品消费
notifyAll();
}
}
// 消费行为
public synchronized void consume( int num ) throws InterruptedException {
// num 表示需要消费的数量,这个数量有可能比实际库存多
// right 表示即将被消费的数量,这个数量有可能比实际库存多
int right = num;
while ( right > 0 ) {
// 当仓库空了,则需要等待 “生产者” 往仓库 生产 商品(为了能有可以消费的商品)
while ( size <= 0 ) {
wait();
}
// “实际消费的数量” —— 实际从仓库里面取出的商品数量
int actual_consume = 0;
/*
* 如果 库存 少于 需要消费的数量,
* 则 实际消费的数量 = 库存
* 否则 实际消费的数量 = 想要消费的数量
*/
actual_consume = (size < right) ? size : right ;
// 仓库取出,size 减少 actual
size -= actual_consume;
// 即将取出的数量会随着仓库取出成功的行为而减少
right -= actual_consume;
System.out.println(Thread.currentThread().getName() + " 需要消费:" + num +
" 仓库实际取出:" + actual_consume +
" 仓库现有库存:" + size +
" 还需要消费:" + right );
// 唤醒 生产者 进行 商品生产
notifyAll();
}
}
}
// 生产者
class Producer {
// 生产者 操作的仓库
private Depot depot;
public Producer( Depot d ) {
this.depot = d;
}
// 生产商品 —— 创建一个线程往仓库里面放入商品
public void fun_produce( int num ) {
new Thread() {
@Override
public void run() {
try {
depot.produce(num);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
// 消费者
class Consumer {
// 消费者 操作的仓库
private Depot depot;
public Consumer( Depot d ) {
this.depot = d;
}
// 消费商品 —— 创建一个线程从仓库里面取出商品
public void fun_Consumer( int num ) {
new Thread() {
@Override
public void run() {
try {
depot.consume(num);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
public class Code_001 {
public static void main(String[] args) {
// 创建仓库 d1
Depot d1 = new Depot(10);
// 生产者 p1
Producer p1 = new Producer(d1);
// 消费者 c1
Consumer c1 = new Consumer(d1);
// 情况1
// p1.fun_produce(7);
// p1.fun_produce(6);
// c1.fun_Consumer(1);
// c1.fun_Consumer(2);
// 情况2 特殊,没有商品进行消费行为
// c1.fun_Consumer(7);
// 情况3
p1.fun_produce(2);
c1.fun_Consumer(7);
p1.fun_produce(1);
p1.fun_produce(4);
}
}
第三种情况的结果
前两种情况可以把代码copy下来自己在本地运行一下
互斥锁的基本用法
之前在用同步锁是通过调用wait函数进行等待,然后调用notifyAll进行全部的唤醒,现在我们就使用
互斥锁来实现对特定的对象进行解锁,这样更加能够满足需求
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Code_003 {
// 创建一个互斥锁
public static Lock lock = new ReentrantLock();
// 利用锁 绑定一个条件
public static Condition condition = lock.newCondition();
// 线程类
static class Thread_03 extends Thread {
@Override
public void run() {
// 加锁
lock.lock();
try {
System.out.println(this.getName() + " 进行唤醒... ");
// notify();
condition.signal();
} finally {
// 解锁
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread_03 t3 = new Thread_03();
t3.setName(" 线程_03 ");
// 加锁
lock.lock();
System.out.println(Thread.currentThread().getName() + " 启动 线程_03 ");
t3.start();
System.out.println(Thread.currentThread().getName() + " 进行 等待... ");
// t3.wait();
condition.await();
System.out.println(Thread.currentThread().getName() + " 执行 结束!! ");
// 解锁
lock.unlock();
}
}
在控制台的结果
基于生产者和消费者模型使用互斥锁
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 简版,不考虑仓库容量,操作行为可以导致负数结果
*
* 完整版,需要考虑仓库容量,操作结构不能为负数
*
*/
class Depot {
private int capacity; // 仓库的容量 - max
private int size; // 实际存放数量
private Lock lock; // 互斥锁
private Condition full; // 放满
private Condition empty; // 取空
public Depot( int num ) {
this.capacity = num;
this.size = 0;
this.lock = new ReentrantLock();
this.full = lock.newCondition();
this.empty = lock.newCondition();
}
// 生产行为
public void produce( int num ) {
// 进方法的第一行代码加锁(第一件事)
lock.lock();
try {
// 即将生产的商品数量
int left = num;
while ( left > 0 ) {
// 如果现有库存满了,需要 “等待” 消费者取仓库取出商品,腾出位置放新的商品
while ( size >= capacity ) {
full.await();
}
// 如果需要放入的数量 + 库存 大于 容量,那么只能放入 容量 - 库存;否则 可以放入需要放入的数量
// 实际放入的商品数量
int actual_produce = ( (size+left) > capacity ) ? (capacity-size) : left;
// 库存增加
size += actual_produce;
// 即将要放入的数量减少
left -= actual_produce;
System.out.println(Thread.currentThread().getName() +
" 需要生产:" + num +
" 实际放入仓库:" + actual_produce +
" 仓库现有库存:" + size +
" 还需要放入:" + left);
// 唤醒 消费者
empty.signal();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
// 消费行为
public void consume( int num ) {
// 加锁
lock.lock();
try {
// 即将消费的商品数量
int right = num;
while ( right > 0 ) {
// 如果现有库存空了,需要 “等待” 生产者往仓库放入商品,才能继续取出商品
while ( size <= 0 ) {
empty.await();
}
// 如果需要取出的数量 大于 库存,那么只能取出 库存;否则 可以取出需要取出的数量
// 实际取出的商品数量
int actual_consume = ( right > size ) ? size : right;
// 库存减少
size -= actual_consume;
// 即将要取出的数量减少
right -= actual_consume;
System.out.println(Thread.currentThread().getName() +
" 需要消费:" + num +
" 实际取出仓库:" + actual_consume +
" 仓库现有库存:" + size +
" 还需要取出:" + right);
// 唤醒 生产者
full.signal();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
// 生产者
class Producer {
private Depot depot;
public Producer( Depot d ) {
this.depot = d;
}
public void fun_produce( int num ) {
new Thread() {
public void run() {
try {
depot.produce(num);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
// 消费者
class Consumer {
private Depot depot;
public Consumer( Depot d ) {
this.depot = d;
}
public void fun_consume( int num ) {
new Thread() {
public void run() {
depot.consume(num);
}
}.start();
}
}
public class Code_001 {
public static void main(String[] args) {
// 创建仓库 d1
Depot d1 = new Depot(10);
// 生产者 p1
Producer p1 = new Producer(d1);
// 消费者 c1
Consumer c1 = new Consumer(d1);
p1.fun_produce(12);
// p1.fun_produce(6);
c1.fun_consume(1);
c1.fun_consume(3);
}
}
在控制台的结果
线程池(★★★★★)
线程池的访问流程
Executors.newFixedThreadPool():固定大小的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread_01 extends Thread{
@Override
public void run() {
System.out.println( Thread.currentThread().getName() + " 执行中...");
}
}
public class Code_001 {
public static void main(String[] args) {
/*
* 固定大小的线程池
*
* 可以指定线程池的大小(可容纳的线程的数量),这种线程池的 corePoolSize 等于 maximumPoolSize
* 在线程池的运行过程中,线程的数量不会变化;
* 有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则进入队列等待
*
* 任务队列的类型是:LinkedBlockingQueue —— 无界
*
*/
ExecutorService pool = Executors.newFixedThreadPool(3);
// 创建线程
Thread t1 = new Thread_01();
Thread t2 = new Thread_01();
Thread t3 = new Thread_01();
Thread t4 = new Thread_01();
Thread t5 = new Thread_01();
Thread t6 = new Thread_01();
Thread t7 = new Thread_01();
Thread t8 = new Thread_01();
Thread t9 = new Thread_01();
// 将线程放入线程池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
pool.execute(t8);
pool.execute(t9);
// 关闭线程池
pool.shutdown();
}
}
在控制台的结果
Executors.newSingleThreadExecutor():单个线程的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread_02 extends Thread{
@Override
public void run() {
System.out.println( Thread.currentThread().getName() + " 执行中...");
}
}
public class Code_002 {
public static void main(String[] args) {
/*
* 单个线程的线程池
*
* 只有一个线程的线程池( corePoolSize 等于 maximumPoolSize 等于 1 )
* 在线程池的运行过程中,线程的数量不会变化;
* 有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则进入队列等待
*
* 任务队列的类型是:LinkedBlockingQueue —— 无界
*
* 意味着所有任务必须严格按照 “ 先进先出 ” 的顺序执行
*/
ExecutorService pool = Executors.newSingleThreadExecutor();
// 创建线程
Thread t1 = new Thread_02();
Thread t2 = new Thread_02();
Thread t3 = new Thread_02();
Thread t4 = new Thread_02();
Thread t5 = new Thread_02();
Thread t6 = new Thread_02();
Thread t7 = new Thread_02();
Thread t8 = new Thread_02();
Thread t9 = new Thread_02();
// 将线程放入线程池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
pool.execute(t8);
pool.execute(t9);
// 关闭线程池
pool.shutdown();
}
}
在控制台的结果
Executors.newCachedThreadPool():缓存线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread_03 extends Thread{
@Override
public void run() {
System.out.println( Thread.currentThread().getName() + " 执行中...");
}
}
public class Code_003 {
public static void main(String[] args) {
/*
* 缓存线程池
*
* 不长期持有固定线程,有新任务就在线程池中增加一个新线程,当该线程执行完任务之后,保留一段时间再销毁
* corePoolSize 等于 0
* maximumPoolSize 等于 随机情况,没有固定值
* KeepAliveTime 默认 60 秒
*
* 在线程池的运行过程中,线程的数量会变化;
* 有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则创建新的线程;
* 线程执行完任务之后,空闲等待时间为60秒(默认),时间到了就释放该线程。
*
* 任务队列的类型是:SynchronousQueue —— 立即执行
*
*/
ExecutorService pool = Executors.newCachedThreadPool();
// 创建线程
Thread t1 = new Thread_03();
Thread t2 = new Thread_03();
Thread t3 = new Thread_03();
Thread t4 = new Thread_03();
Thread t5 = new Thread_03();
Thread t6 = new Thread_03();
Thread t7 = new Thread_03();
Thread t8 = new Thread_03();
Thread t9 = new Thread_03();
// 将线程放入线程池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
pool.execute(t8);
pool.execute(t9);
// 关闭线程池
pool.shutdown();
}
}
在控制台的结果
ScheduledThreadPoolExecutor(1):定时执行的线程池
package 多线程.Day_04_16_Code.Day_04_16_Code;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Code_004 {
public static void main(String[] args) {
/*
* 定时执行的线程池
*
* 在设置时间规则之后,可以一直执行下去
*
*
*
*/
ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
pool.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
System.out.println( Thread.currentThread().getName() + " 执行中...");
}
}
, 0, 2, TimeUnit.SECONDS);
}
}
执行的结果,每两秒执行线程一次
接下来的部分会接着整理,继续努力