1. 线程
- 线程开始需要 new Thread(对象,“名字”).start
- 其他需要用到Thread的地方不需要new
- 启动线程需要new Thread
- Thread调用方法不需要new
- 重写的Run方法是线程,线程内放执行的操作
2. 继承Thread类:
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象. start()
- 不建议使用:避免OOP单继承局限性
- 无参
package com.xiaojia;
public class Demo01 extends Thread{
public static void main(String[] args) {
new Demo01().start();
/*
此段代码要写在main方法的输出语句的前面
否则会出现main方法中的 我在看代码--> 输出完才开始输出我在学习多线程-->的情况
*/
for (int i = 0; i < 500; i++) {
System.out.println("我在看代码-->"+i);
}
}
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("我在学习多线程-->"+i);
}
}
}
- 有参
package com.xiaojia;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class Demo01 extends Thread{
public static void main(String[] args) {
new Demo01("https://tse1-mm.cn.bing.net/th/id/OIP.5xQ4rsV36HO6J5zA4CP0QAHaNK?w=179&h=319&c=7&o=5&pid=1.7", "1.jpg").start();;
new Demo01("https://tse2-mm.cn.bing.net/th/id/OIP.V42xnW-bEEPFVt3JZSt3hAHaNJ?w=179&h=319&c=7&o=5&pid=1.7", "2.jpg").start();;
new Demo01("https://tse2-mm.cn.bing.net/th/id/OIP.6nX818sT5um1if-WaNxQsAHaNK?w=179&h=319&c=7&o=5&pid=1.7", "3.jpg").start();;
}
private String url;
private String name;
public Demo01(String url,String name){
this.url = url;
this.name = name;
/*
使用this的时候,这个方法外要有定义的属性,不然会出现错误
*/
}
@Override
public void run() {
new WebDownLoader().downloader(url,name);
System.out.println("下载了图片"+name);
}
}
class WebDownLoader{
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 实现Runnable接口
- 实现接口runnable具备多线程能力
- 启动线程:输入目标对象+Thread对象. start()
- new Thread(testStop).start();
- 推荐使用:灵活方便,方便同一个对象被多个线程使用
package com.xiaojia;
public class Demo01 implements Runnable{
public static void main(String[] args) {
new Thread(new Demo01()).start();
/*
Runnable接口,开启线程时Thread内需要参数
*/
for (int i = 0; i < 500; i++) {
System.out.println("我在看代码-->"+i);
}
}
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
4. 注意点
- 如果线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
public class Test implements Runnable{
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run....Thread"+i++);
}
}
public static void main(String[] args) {
Test testp = new Test();
new Thread(test).start();
}
}
//独立的,没有调用run方法,不执行任何操作
- 并不是一启动线程(调用start()方法)就执行这个线程,而是进入就绪状态,什么时候运行要看CUP。
5. 线程睡眠
- 每一个对象都有一把锁,sleep不会释放锁;
- 模拟延时,放大事情的发生性
6. 线程礼让
- 让CPU重新调度,礼让不一定成功,看CPU心情
package com.xiaojia;
public class Demo01 implements Runnable{
public static void main(String[] args) {
Demo01 demo01 = new Demo01();
new Thread(demo01,"a").start();
new Thread(demo01,"b").start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程结束执行");
}
}
7. 线程状态
- start(),join(),以及get/set相当于方法调用,需要new Thread,即Thread的对象thread
- sleep,yield,State以及其他则不需要new Thread,直接 Thread.sleep即可
- 线程被中断或者结束就不能再次启动
- NEW
至今尚未启动的线程 - RUNNABLE
正在 Java 虚拟机中执行的线程 - BLOCKED
被阻塞等待监视器锁定的线程 - WAITING
正在等待另一个线程执行特定动作的线程 - TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的操作的线程 - TERMINATED
已退出的线程
8. 线程优先级
- getPriority(),setpriority(int xxx)
- 线程优先级用数字表示,范围1-10
- 优先级低表示被调度的几率低,先调度谁看CPU心情
- 优先级设置在start()前使用
- 主线程默认优先级为5,不能改变
package com.xiaojia;
public class Demo01{
public static void main(String[] args) {
MyPriority myPriority = new MyPriority();
Thread thread1 = new Thread(myPriority);
Thread thread2 = new Thread(myPriority);
Thread thread3 = new Thread(myPriority);
Thread thread4 = new Thread(myPriority);
Thread thread5 = new Thread(myPriority);
Thread thread6 = new Thread(myPriority);
thread1.setPriority(Thread.MIN_PRIORITY);
thread1.start();//Thread-0-->1
thread2.setPriority(3);
thread2.start();//Thread-1-->3
thread3.start();//Thread-2-->5
thread4.setPriority(Thread.NORM_PRIORITY);
thread4.start();//Thread-3-->5
thread5.setPriority(7);
thread5.start();//Thread-4-->7
thread6.setPriority(Thread.MAX_PRIORITY);
thread6.start();//Thread-5-->10
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
9. 守护线程
- daemon
- thread.setDaemon(true);
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
package com.xiaojia;
public class Demo01{
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);
/*
true代表是守护线程,这句话应该放在守护线程开启的上方
守护线程在用户线程执行完毕后自动结束
*/
thread.start();
new Thread(you).start();
}
}
class God implements Runnable {
@Override
public void run() {
while (true){
System.out.println("上帝保佑着你!");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都开心的活着-->"+i);
}
System.out.println("=====GoodBye,World=====");
}
}
10. lambda表达式
语法
- lamb的类型是一个接口,lambda表达式的本身就是一个接口的实现
- (params) -> expression[表达式]
- (params) -> statement[语句]
- (params) -> {statements}
- a -> System.out.println(“I like lambda -->”+ a)
- new Thread(() -> System.out.println(“多线程学习”)).start();
- 函数式接口:
- 接口只有一个方法
- 避免匿名内部类定义过多
- 可以让你的代码看起来很简洁
- 去掉一堆没有意义的代码,只留下核心的逻辑
11. 线程同步
- synchronized
- public synchronized void method(int args){}
- 同步块:synchronized (对象){}
- 多个线程操作同一个资源
- 队列+锁,保证线程安全性
- 一个线程持有锁,会导致其他需要此锁的线程挂起
- 损失性能
- 优先级高的等待一个优先级低的线程释放锁,会导致优先级倒置
12. synchronized
- 隐形的锁
- 每个线程只有一个对象能加锁
13. 死锁:
- 产生的必要条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对方获得的资源保持不放
- 不剥夺条件:进城已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
- 避免死锁
- 破坏四个必要条件中的一个或多个就可以避免死锁的产生
package com.xiaojia;
public class Demo01 {
public static void main(String[] args) {
Makeup girlfriend1 = new Makeup(0,"第一任女朋友");
Makeup girlfriend2 = new Makeup(1,"第二任女朋友");
girlfriend1.start();
girlfriend2.start();
}
}
class Lipstick{
}
class Mirror{
}
class Makeup extends Thread{
int choose;
String girlfriend;
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
/*
static不能去掉,synchronized锁的静态对象
*/
public Makeup(int choose,String girlfriend){
this.choose = choose;
this.girlfriend = girlfriend;
}
@Override
public void run() {
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void makeup() throws InterruptedException {
if (choose == 0){
synchronized (lipstick) {
System.out.println(this.girlfriend + "获得口红的锁");
Thread.sleep(1000);
synchronized (mirror) {
System.out.println(this.girlfriend + "想获得镜子的锁");
}
}
}else {
synchronized (mirror) {
System.out.println(this.girlfriend + "获得镜子的锁");
Thread.sleep(2000);
synchronized (lipstick) {
System.out.println(this.girlfriend + "获得口红的锁");
}
}
}
}
}
14. lock
- 显性的锁
- ReentrantLock:可重入锁
- 每个线程只有一个对象能加锁
15. synchronized与lock对比
- lock实现时锁,需要手动打开和关闭
synchronized是隐形锁,出了作用域自动释放 - lock只有代码块锁
synchronized有代码块锁和方法锁 - lock锁,JVM将花费较少的时间去调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
- 优先级顺序:
- lock>同步代码块(已经入方法体,分配了相应资源)>同步方法(在方法体之外)
16. 线程协作
- 管程法
package com.xiaojia;
public class Demo01 {
public static void main(String[] args) {
Containe containe = new Containe();
Consumer consumer = new Consumer(containe);
Productor productor = new Productor(containe);
new Thread(consumer,"消费者").start();
new Thread(productor,"生产者").start();
}
}
//生产者
class Productor implements Runnable{
Containe containe = new Containe();
//生产产品放在容器中
public Productor(Containe containe){
this.containe = containe;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
containe.push(new Chicken(i));
System.out.println(Thread.currentThread().getName()+"生产了"+i+"只鸡");
}
}
}
//消费者
class Consumer implements Runnable{
Containe containe = new Containe();
//在容器中取出产品消费
public Consumer(Containe containe){
this.containe = containe;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
containe.pop(new Chicken(i));
System.out.println(Thread.currentThread().getName()+"消费了"+i+"只鸡");
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//容器
class Containe{
int count = 0;
//容器能放10个产品
Chicken[] chickens = new Chicken[10];
//生产者放入产品
public synchronized void push(Chicken chicken){
//如果产品满了,通知消费者消费,生产者等待
if (count == chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[count] = chicken;
count++;
this.notifyAll();
}
//消费者消费产品
public synchronized void pop(Chicken chicken){
if (count == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
chickens[count] = chicken;
this.notifyAll();
}
}
- 信号灯法
package com.xiaojia.demo07;
//线程协作:测试生产者消费者模型-->信号灯法:标志为解决
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者-->演员
class Player extends Thread{
TV tv;
public Player(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2 == 0){
this.tv.play("小贾java课程播放中");
}else {
this.tv.play("广告中");
}
}
}
}
//消费者-->观众
class Watcher extends Thread{
TV tv;
public Watcher(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//产品-->节目
class TV{
//演员表演,观众等待 T
//观众观看,演员等待 F
String voice;//表演的节目
boolean flag = true;
//表演
public synchronized void play(String voice){
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.voice = voice;
System.out.println("演员表演了:"+voice);
//通知观众观看
this.notifyAll();//通知唤醒
this.flag = !this.flag;
}
//观看
public synchronized void watch(){
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看了:"+voice);
//通知演员表演
this.notifyAll();//通知唤醒
this.flag = !this.flag;
}
}
17. 线程加入
package com.xiaojia;
public class Demo01 implements Runnable {
public static void main(String[] args) {
Demo01 demo01 = new Demo01();
Thread thread = new Thread(demo01);
thread.start();
for (int i = 0; i < 1000; i++) {
if (i == 600){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main-->"+i);
}
}
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("join-->"+i);
}
}
}
/*
* join线程是在某一时刻加入其他线程内部的,就好比插队现象
* 线程启动后,main线程和join线程一起跑,
* 当主线程跑到 i==600 时
* main线程停下,等待join线程跑完
* join线程跑完,main线程跟着跑完
* */
18. 线程停止
package com.xiaojia;
public class Demo01 implements Runnable{
public static void main(String[] args) {
Demo01 demo01 = new Demo01();
new Thread(demo01).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main-->"+i);
if (i==500){
demo01.stop();
System.out.println("线程该停止了");
}
}
}
public void stop(){
flag = false;
}
private boolean flag = true;
int i = 0;
//定义 i 如果放入while循环内,则 i 的值一直被重置为0
@Override
public void run() {
while (flag){
System.out.println("线程运行-->"+i++);
}
}
}
19. 线程池
- API查看ExecutorService和Executor
- ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令没有返回值,一般用来执行Runnable
- Futuresubmit(Callable task):执行任务,有返回值一般用来执行Callable
- void shutdown():关闭线程池
- Executor:工具类、线程池的工厂类,用来创建并返回不同类型的线程池
package com.xiaojia.demo07;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//测试线程池
public class TestPool {
public static void main(String[] args) {
//1. 创建服务,创建线程池
//newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2. 关闭链接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}