一:基础部分
- 并发与并行:
- 并发 :同一个时间段内
- 并行 :同一时刻
- 进程与线程:
- 进程:内存中运行的一个应用程序
- 线程: 一个进程中至少有一个线程
image.png
- 线程调度:
- 分时调度:所有线程轮流使用cpu的使用权
- 抢占调度:(java) 优先级高的线程使用cpu
- Thread.sleep(); //静态方法 可直接使用
- 线程的实现方法:
- 继承Thread类方法,@Override run方法
- 实现Runnable接口 (避免单一继承,扩展性更高)
- 线程安全问题指的是: 对共享变量的修改。
- 线程启动方式。Thread thread = new Thread(r); //r为runable的实现类
- start() 是启动一个新线程,run()不启动
- wait(long) 如果在long时间内没有唤醒 则自己醒
- notify()随性唤醒一个线程
notifyAll()唤醒所有的等待线程 - 线程通信:多个线程处理同共享资源时但是处理的动作不同,比如说一个吃包子,一个生产包子
- 线程池: 存有好多线程的集合,用的时候取,用完归还。
二: 案例(卖票问题,三个窗口同时卖票)
- 不使用锁
Ticket 类
public class Ticket implements Runnable {
private Integer num = 100;
@Override
public void run() {
while(true){
if(num>0){
// Thread.sleep(100); //使用休眠可使安全问题更加暴露
System.out.println(Thread.currentThread().getName()+" sell the "+num);
num--;
}
}
}
}
测试类
public class TicketTest {
public static void main(String[] args) {
Runnable run = new Ticket();
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
Thread t3 = new Thread(run);
t1.start();
t2.start();
t3.start();
}
}
结果:出现了重复卖票,和卖不存在的票
分析:当一个线程执行到if()时,当一个线程执行时,另一个线程也在执行这段代码,所以会出现问题。(加Thread可以让线程失去对cpu的执行权)
二. 解决方案 (synchronized)
- synchronized 同步代码块
- synchronized 同步方法
- synchronized 静态方法
使用同步方法
public class Ticket implements Runnable {
private Integer num = 100;
public synchronized void sell(){
while(true){
if(num>0){
// Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" sell the "+num);
num--;
}
}
}
@Override
public void run() {
sell();
}
}
三. 解决方案(Lock)
public class Ticket implements Runnable {
private Integer num = 100;
private Lock l = new ReentrantLock();
@Override
public void run() {
while(true){
l.lock();
if(num>0){
// Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" sell the "+num);
num--;
}
l.unlock();
}
}
}
三:线程的状态
- 线程通信->等待唤醒案例代码实现(synchronized同步代码块)
public class DinnerTest {
private Object obj = new Object();
public static void main(String[] args) {
Object obj = new Object();
//顾客线程
new Thread() {
@Override
public void run() {
synchronized (obj){
System.out.println("顾客点餐了");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客吃饭喽");
}
}
}.start();
//厨师线程
new Thread() {
@Override
public void run() {
synchronized (obj){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("厨师做饭完毕");
obj.notify();
}
}
}.start();
}
}
四:线程池的实现
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new MyThread());
es.submit(new MyThread());
es.submit(new MyThread());
}
输出
pool-1-thread-1正在执行
pool-1-thread-2正在执行
pool-1-thread-1正在执行
线程池里只有两个线程,有三个任务,所以第三个任务会等待一个任务完成释放线程后再进行。
网友评论