多线程基础

多线程基础

Java.Thread

多线程概述

线程简介

任务、进程、线程、多线程

线程实现(重点)

线程状态

线程同步(重点)

线程通信问题

高级主题

线程、进程、多线程

线程

多任务

现实中太多这样同时做多件事情的例子了,看起来是多个任务都在做,其实本质上我们 的大脑在同一时间依旧只做了一件事情。

多线程

多线程例子(生活,游戏,编程)

原来是一条路,慢慢因为车太多了,道路堵塞,效率极低。 为了提高使用的效率,能够充分利用道路,于是加了多个车道。

并发

普通方法调用和多线程

在这里插入图片描述

在操作系统中运行的程序就是进程,比如你的 QQ,播放器,游戏,IDE等

声音 字幕 图像 进程

一个进程可以有多个线程,如视频中同时听声音,看图像,看弹幕等

process与thread

  • 说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。

  • 而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位

  • 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。

注意:

很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。

如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。

本章核心概念 :

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main() 称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与 操作系统紧密相关的,先后顺序是不能认为的干预的。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销。
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

继承Thread类

线程创建

Thread 、Runnable、Callable

三种创建方式

Thread class => 继承Thread类(重点)

Runnable接口 => 实现Runnable接口(重点)

Callable接口 => 实现Callable接口(了解)

Thread

学习一个类,首先查看JDK帮助文档

  • 自定义线程类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
public class StartThread extends Thread{
    //线程入口点
    @override
    public void run(){
        //线程体
        for (int i = 0;i < 20;i++){
            System.out.println("我在学习多线程---");
        }
    }
}

线程不一定立即执行,CPU安排调度

public static void main(String[] args){
    //创建线程对象
    StartThread t = new StartThread();
    t.start();
}
package com.feng.demo;

/*
创建线程
方式一:继承Thread类,重写run()方法,调用start开启线程
 */

public class TestThread1 extends Thread {

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }

    public static void main(String[] args) {
        //main线程,主线程

        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();

        //调用start开启线程
        testThread1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在敲代码---"+i);
        }
    }
}
//总结:线程开启不一定立即执行,由CPU调度执行

网图下载

范例:下载图片

引入:Commons IO包,工具类库

  • new package,命名为lib
  • 百度搜索Commons IO,拷贝到项目lib里面。
  • add as library
//文件下载工具类
class WebDownloader{
    //远程路径,存储名字
    public void downloader(String url,String name){
        try{
            //Commons IO是针对开发IO流功能的工具类库
            //FileUtils文件工具,复制url到文件
            FileUtils.copyURLToFile(new URL(url),new File(name));
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("文件下载失败")}
    }
}
@Override
public void run(){
    WebDownloader webDownloader = new WebDownloader();
    webDownloader.downloader(url,name);
    System.out.println(name);
}
public static void main(String[] args){
    StartThread2 t1 = new StartThread2;
    StartThread2 t2 = new StartThread2;
    StartThread2 t3 = new StartThread2;
    
    //启动三个线程
    t1.start();
    t2.start();
    t3.start();
    
}
package com.feng.demo;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread{

    private String url;  //网络图片地址
    private String name;  //保存的文件名

    public TestThread2(String url,String name){
        this.url = url;
        this.name = name;

    }
    //下载图片线程的执行体
    @Override
    public void run(){
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);

    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img9.51tietu.net/pic/2019-091301/v1e3d2do0dsv1e3d2do0ds.jpg","1.jpg");
        TestThread2 t2 = new TestThread2("https://img9.51tietu.net/pic/2019-091301/v1e3d2do0dsv1e3d2do0ds.jpg","2.jpg");
        TestThread2 t3 = new TestThread2("https://img9.51tietu.net/pic/2019-091301/v1e3d2do0dsv1e3d2do0ds.jpg","3.jpg");

        //线程同时执行的
        t1.start();
        t2.start();
        t3.start();

    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}
//找不到或无法加载主类,save all再试一试

实现Runnable接口

查看JDK帮助文档

  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
public class StartThread3 implements Runnable{
    @Override
    public void run(){
        //线程体
        for(int i = 0;i < 20;i++){
            System.out.println("我在学习多线程---")}
    }
}
//创建实现类对象
StartThread3 st = new StartThread3();
//创建代理类对象
Thread thread = new Thread(st);
//启动
thread.start();

推荐使用Runnable对象,因为Java单继承的局限性

小结

  • 继承Thread类
    • 子类继承Thread类具备多线程能力
    • 启动线程:子类对象.start()
    • 不建议使用:避免OOP单继承局限性
  • 实现Runnable接口
    • 实现接口Runnable具有多线程能力
    • 启动线程:传入目标对象+thread对象.start()
    • 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
//一份资源
StartThread startion = new StartThread();
//多个代理
new Thread(station,name:"小黎").start();
new Thread(station,name:"小海").start();
new Thread(station,name:"小桃").start();
package com.feng.demo;

/*
创建线程
方式二:实现Runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法。
 */

public class TestThread3 implements Runnable{
    @Override
    public void run(){
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程---"+i);

        }
    }

    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();

        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testThread3);
        thread.start();
        
        //new Thread(testThread3).start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在敲代码---"+i);

        }

    }
}

初识并发问题

package com.feng.demo;

//多个线程同时操作同一个对象
//买火车票的例子

//发现问题,多个线程同时操作同一个资源的情况下,线程不安全,数据混乱

public class TestThread4 implements Runnable{

    //票数
    private int ticketNums = 10;

    @Override
    public void run(){
        while(true){
            if(ticketNums <= 0){
                break;
            }

            //模拟延时
            try {
                Thread.sleep(200);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第" +ticketNums--+"票");
            //ticketNums--
        }
    }

    public static void main(String[] args) {

        TestThread4 ticket = new TestThread4();

        new Thread(ticket,"小黎").start();
        new Thread(ticket,"小海").start();
        new Thread(ticket,"小桃").start();
        //点一点ticket "" 就会出现 name:

    }
}

龟兔赛跑-race

  1. 首先来个赛道距离,然后要离终点越来越近
  2. 判断比赛是否结束
  3. 打印出胜利者
  4. 龟兔赛跑开始
  5. 故事中是乌龟赢的,兔子需要睡觉,所以我们来模拟兔子睡觉
  6. 终于,乌龟赢得比赛
package com.feng.demo;

//模拟龟兔赛跑
public class RaceThread5 implements Runnable{

    //胜利者
    private static String winner;

    @Override
    public void run(){
        for (int i = 0; i <= 100; i++) {

            //模拟兔子休息
            if(Thread.currentThread().getName().equals("兔子")&& i%10==0){
                try {
                    Thread.sleep(100);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }

            }

            //判断比赛是否结束
            boolean flag = gameOver(i);
            //如果比赛结束了就停止
            if(flag){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
        }
    }


    //判断是否完成比赛
    private boolean gameOver(int steps){
        //判断是否有胜利者
        if(winner!=null) {  //已经存在胜利者了
            return true;
        }{
            if(steps==100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is"+winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        RaceThread5 raceThread5 = new RaceThread5();

        new Thread(raceThread5,"兔子").start();
        new Thread(raceThread5,"乌龟").start();

    }
}

实现Callable接口

静态代理模式

Lamda表达式

线程停止

线程休眠_sleep

线程礼让_yield

线程强制执行_join

观测线程状态

线程的优先级

守护线程

线程同步机制

三大不安全案例

同步方法及同步块

CopyOnWriteArrayList

死锁

Lock锁

生产者消费者问题

管程法

信号灯法

线程池

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值