什么是多线程
线程
进程
为什么要有多线程
应用场景
多线程的两个概念
并发 在同一时刻 有多个指令在单个CPU上交替执行
并行 在同一时刻 有多个指令在多个CPU上同时执行
多线程的实现方式
- 继承Thread类的方式进行实现
- 实现Runnable接口的方式进行实现
- 利用Callable接口和Future接口方式实现
继承Thread类的方式进行实现
代码示例
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + "hello world"); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Main { public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); MyThread1 t2 = new MyThread1(); t1.setName("线程1"); t2.setName("线程2"); t1.start(); t2.start(); } }
|
实现Runnable接口的方式进行实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MyRun implements Runnable{ @Override public void run() {
for (int i = 0; i < 100; i++) { Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "hello"); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Main { public static void main(String[] args) {
MyRun myRun = new MyRun(); Thread t3 = new Thread(myRun); Thread t4 = new Thread(myRun); t3.setName("线程3"); t4.setName("线程4"); t3.start(); t4.start();
} }
|
实现Callable接口
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable(); FutureTask<Integer> futureTask = new FutureTask<>(myCallable); Thread t5 = new Thread(futureTask); t5.start();
Integer ans = futureTask.get(); System.out.println(ans);
} }
|
常见的成员方法
基础方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MyThread2 extends Thread{ public MyThread2() {
}
public MyThread2(String name) { super(name); for (int i = 0; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println(getName() + "@" + i); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class Main { public static void main(String[] args) throws InterruptedException {
MyThread2 t1 = new MyThread2("aa"); MyThread2 t2 = new MyThread2("bb");
t1.start(); t2.start();
Thread t = Thread.currentThread(); String name = t.getName(); System.out.println(name);
Thread.sleep(5000);
} }
|
线程优先级
java采取的线程调度 是抢占式调度
1 2 3 4 5 6 7 8 9
| public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Main { public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread("aa"); Thread t2 = new Thread("bb");
t1.setPriority(1); t2.setPriority(10);
t1.start(); t2.start(); } }
|
守护线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Main { public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); MyThread2 t2 = new MyThread2();
t1.setName("aa"); t2.setName("bb");
t2.setDaemon(true); } }
|
礼让线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Main { public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); MyThread1 t2 = new MyThread1();
t1.setName("aa"); t2.setName("bb");
t1.start(); t2.start(); } }
|
插入线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Main { public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); t1.setName("土豆"); t1.start();
for (int i = 0; i < 10; i++) { System.out.println("main线程" + i); } } }
|
线程的生命周期
问: sleep方法会让线程睡眠 睡眠时间到了之后 立马就会执行下面的代码吗?
不会因为线程在进入就绪状态后还要有CPU资源才行
线程安全
示例:
买票引发的安全问题:
- 相同的票出现了多次
- 出现了超出范围的票
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MyThread extends Thread{ static int ticket = 0;
@Override public void run() { while (true){ if(ticket < 100){ try { Thread.sleep(100); }catch (InterruptedException e){ e.printStackTrace(); }
ticket++; System.out.println(getName() + "正在卖第" + ticket ); }else { break; }
} } }
|
原因:
线程执行的随机性
同步代码块
把操作共享数据的代码锁起来
格式
1 2 3
| synchronized (锁){ 操作共享数据的代码 }
|
特点1: 锁默认打开 有一个线程进去了 锁自动关闭
特点2: 里面的代码全部执行完毕 线程出来 锁自动打开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MyThread extends Thread{ static int ticket = 0;
@Override public void run() {
while (true){ synchronized (MyThread.class){ if(ticket < 100){ try { Thread.sleep(100); }catch (InterruptedException e){ e.printStackTrace(); }
ticket++; System.out.println(getName() + "正在卖第" + ticket ); }else { break; } }
} } }
|
同步方法
就是把synchronized 关键字加到方法上
格式:
修饰符就是把synchronized 返回值类型 方法名(方法参数){…}
特点1: 同步方法是锁住方法里面所有的代码
特点2: 锁对象不能自己指定
非静态: this (当前方法的调用者)
静态: 当前类的字节码文件对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class MyRunnable implements Runnable{ int ticket = 0; @Override public void run() {
while (true){ if (method()){ break; } } }
private synchronized boolean method(){ if (ticket == 100){ return true; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
ticket++; System.out.println(Thread.currentThread().getName() + " " + ticket); } return false; } }
|
lock锁
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class MyThread extends Thread{ static int ticket = 0; static Lock lock = new ReentrantLock();
@Override public void run() { while (true){ lock.lock();
try { if(ticket == 100){ lock.unlock(); break; }else { Thread.sleep(10); ticket++; System.out.println(getName() + "在卖第" + ticket); } } catch (InterruptedException e) { throw new RuntimeException(e); }finally { lock.unlock(); } } } }
|
死锁
等待唤醒机制
生产者和消费者(等待唤醒机制)
等待唤醒机制 基础实现
代码示例
消费者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class Foodie extends Thread{
@Override public void run() {
while (true){ synchronized (Desk.lock){ if(Desk.count == 0){ break; }else { if(Desk.foodFlag == 0){ try { Desk.lock.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } }else{ Desk.count--; System.out.println("正在吃 还能吃" + Desk.count + "碗!" ); Desk.lock.notifyAll(); Desk.foodFlag = 0; }
} } } } }
|
生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Cook extends Thread{ @Override public void run() { while (true){ synchronized (Desk.lock){ if (Desk.count == 0){ break; }else { if (Desk.foodFlag == 1){ try { Desk.lock.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } }else { System.out.println("厨房做了一碗面条"); Desk.foodFlag = 1; Desk.lock.notifyAll(); }
} } } } }
|
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class ThreadDemo { public static void main(String[] args) {
Cook cook = new Cook(); Foodie foodie = new Foodie();
cook.setName("厨师"); foodie.setName("吃货");
cook.start(); foodie.start(); } }
|
等待唤醒机制 阻塞队列实现
消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.util.concurrent.ArrayBlockingQueue;
public class Foodie extends Thread{
ArrayBlockingQueue<String>queue;
public Foodie(ArrayBlockingQueue<String> queue) { this.queue = queue; }
@Override public void run() { while (true){ try { String food = queue.take(); System.out.println(food); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.util.concurrent.ArrayBlockingQueue;
public class Cook extends Thread{
ArrayBlockingQueue<String>queue;
public Cook(ArrayBlockingQueue<String> queue) { this.queue = queue; }
@Override public void run() { while (true){ try { queue.put("面条"); System.out.println("厨师放了一碗面条"); } catch (InterruptedException e) { e.printStackTrace(); } }
} }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.util.concurrent.ArrayBlockingQueue;
public class ThreadDemo { public static void main(String[] args) {
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
Cook cook = new Cook(queue); Foodie foodie = new Foodie(queue);
cook.start(); foodie.start();
} }
|
线程的状态
线程池
代码实现
代码示例
1 2 3 4 5 6 7
| ExecutorService pool1 = Executors.newCachedThreadPool();
ExecutorService pool2 = Executors.newFixedThreadPool(3);
|
自定义线程池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.util.concurrent.*;
public class MyThreadPoolDemo2 { public static void main(String[] args) { ThreadPoolExecutor pool = new ThreadPoolExecutor( 3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );
} }
|
线程池多大合适呢?
1 2 3 4 5 6 7 8
| public class MyThreadPoolDemo3 { public static void main(String[] args) { int count = Runtime.getRuntime().availableProcessors(); System.out.println(count); } }
|