多线程

程序、进程、线程

在操作系统中运行的程序就是进程,比如QQ、播放器、游戏、IDE等等
一个进程可以有多个线程,如视频中同时听声音,看图像,看弹幕,等等

Process与Thread

说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。
线程

多线程

概念:

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

实现多线程的三种方法:

1、继承Thread类 重写run方法 使用start开启线程

public class student extends  Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我在玩手机");
        }
    }
}
public class Application {
    public static void main(String[] args) {
        student student = new student();
        student.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("我在玩看电视呢");
        }
}}

多线程下载图片

package oop;

import org.apache.commons.io.FileUtils;

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

public class webdownloader extends Thread{
    private  String url;
    private  String file;

    public void webdownloader(String url,String file) {
        this.url=url;
        this.file=file;
    }

    @Override
    public void run() {
        loader loader = new loader();
        loader.loader(url,file);
        System.out.println("下载了"+file);
    }
}
class loader{
    public void loader(String url,String file) {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(file));
        } catch (IOException e) {
            System.out.println("出现异常啦");
            throw new RuntimeException(e);
        }
    }
}
package oop;
import static java.lang.Math.random;
public class Application {
    public static void main(String[] args) {

        webdownloader t1 = new webdownloader();
        webdownloader t2 = new webdownloader();
        webdownloader t3 = new webdownloader();
        t1.webdownloader("https://i0.hdslb.com/bfs/banner/39bb071c9afff5fbb461107562a82b51a4b8e859.jpg@976w_550h_1c.webp","p1.jpg");
        t2.webdownloader("https://i0.hdslb.com/bfs/banner/5bce62f82a1def76993fd16fe058477c68f41021.jpg@976w_550h_1c.webp","p2.jpg");
        t3.webdownloader("https://i0.hdslb.com/bfs/archive/95fdcdf38b3d557c1ce9463cbae49f5bbafc0fd9.jpg@672w_378h_1c.webp","p3.jpg");
        t1.start();
        t2.start();
        t3.start();
    }



}

输出:
下载了p3.jpg
下载了p1.jpg
下载了p2.jpg

实现Runnable接口,重写run方法,将实现的对象传递给Thread中

package oop;
import static java.lang.Math.random;
public class Application {
    public static void main(String[] args) {
        webdownloader t1 = new webdownloader();
        webdownloader t2 = new webdownloader();
        webdownloader t3 = new webdownloader();
     t1.webdownloader("https://i0.hdslb.com/bfs/banner/39bb071c9afff5fbb461107562a82b51a4b8e859.jpg@976w_550h_1c.webp","p1.jpg");
        t2.webdownloader("https://i0.hdslb.com/bfs/banner/5bce62f82a1def76993fd16fe058477c68f41021.jpg@976w_550h_1c.webp","p2.jpg");
        t3.webdownloader("https://i0.hdslb.com/bfs/archive/95fdcdf38b3d557c1ce9463cbae49f5bbafc0fd9.jpg@672w_378h_1c.webp","p3.jpg");
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
}}

小结:推荐使用runnable接口,可以避免单继承的局限性

lambdar表达式

限制:接口中只能有一个约束的方法。

用途:当我们需要一个方法体仅仅使用一次的时候,可以大大简化代码量

public interface testInter {
    public abstract void fun1();
}
testInter inter = null;
        inter = () -> {
            System.out.println("有意思");
        };
        inter.fun1();

线程停止

线程需要手动的释放掉,但是不建议用thread中自带的stop方法,但是可以自己手动停止

package oop;
import static java.lang.Math.random;
public class Application {
    public static void main(String[] args) {
        Thread2 thread = new Thread2();
        new Thread(thread).start();

        for (int i = 0; i < 200; i++) {
            System.out.println("也在runnnnnnnn"+i);
            if (i==60)thread.stop();
        }
    }}
package oop;

public class Thread2 implements  Runnable{
    boolean flag = true;
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            if (flag){System.out.println("runnnnnnnnnnThread"+i);}
            else break;
        }
    }
    public  void stop(){
        flag =false;
    }
}

线程礼让

礼让线程,让当前正在执行的线程暂停,但不阻塞

将线程从运行状态转为就绪状态

让cpu重新调度,礼让不一定成功!要看cpu心情!

守护线程

package oop;
public class testpriority {
    public static void main(String[] args) {
        Thread god = new Thread(() -> {
            while (true) System.out.println("上帝会一直保佑你");
        });
        Thread you = new Thread(() -> {
            for (int i = 0; i <= 36500; i++) {
                System.out.println("每天都很开心的活着");
                if (i==36500) System.out.println("bye world~");
            }
        });
        god.setDaemon(true); // 默认的线程是false修改为true之后就变成了守护线程
        god.start();
        you.start();
    }
    }

线程锁

synchronized(object){}  注意:object是可以变的属性

自己带锁的数组CopyOnWriteArrayList

import java.util.concurrent.CopyOnWriteArrayList;
public class list {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList le = new CopyOnWriteArrayList();

            for (int i = 0; i < 10000; i++) {
                new Thread(()-> {
                    le.add(Thread.currentThread().getName());
                }).start();

                }
        Thread.sleep(200);
        System.out.println(le.size());
        }

死锁

每个对象都有一把自己的锁,当使用两个线程相互要使用对象对方对象的时候,这就会造成二者陷入矛盾中,这就是死锁,而解决死锁的方法也很简单,就是将两个对象独立出来

线程池

package Threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class pool {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new test());
        service.execute(new test());
        service.execute(new test());
        service.execute(new test());

        service.shutdown();
    }
}

class test implements  Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

posted on 2022-07-25 21:33  clinch  阅读(58)  评论(0编辑  收藏  举报