多线程1.22

多线程:

​ 多线程是指在程序中包含多个执行流,也就是说在一个程序中同时运行多个不同的线程来执行不同的任务

线程与进程:

进程:系统资源分配的基本单位。一个在内存中运行的应用程序

线程:cpu调度和执行的单位。进程中的一个执行任务

同一进程下的线程共享进程的地址空间和资源

每个进程之间的地址空间和资源都是相互独立的

一个进程崩溃,在保护模式下不会对其他线程造成影响

一个线程崩溃,整个进程死掉

并发编程的三要素:原子性可见性有序性

用户线程与守护线程:

​ 用户线程:运行在前台,执行具体任务。

​ 守护线程:运行在后台,为用户线程服务。

main函数就是一个用户线程,main函数在启动的同时,JVM还启动了好多守护线程,例如垃圾回收线程。

当用户线程结束,JVM退出,不考虑有没有守护线程的存在。

package com.zql.demo02;

public class TestDeamon {

    public static void main(String[] args) {
        //创建守护线程
        God god = new God();
        Thread thread = new Thread(god);
        //设置为守护线程
        thread.setDaemon(true);
        thread.start();
        //创建用户线程
        You you = new You();
        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 < 100; i++) {
            System.out.println("活了" + i + "年");
        }
    }
}

线程死锁:

​ 死锁是指两个或者两个以上的进程(线程)在执行过程中,由于竞争资源或者是通信造成的阻塞现象。

造成死锁的四个必要条件:

​ 1.互斥条件:线程(进程)对于分配到的资源具有排他性,一个资源只可以被一个线程(进程)占用

​ 2.请求与保持条件:当一个线程(进程)因为请求的资源被占用而发生阻塞,对于已经获得的资源保持不放

​ 3.不剥夺条件:线程(进程)已经获得的资源在未使用完成之前不能被其他线程强行剥夺

​ 4.循环等待条件:发生死锁时,所等待的线程(进程)会形成一个环路,类似于死循环,造成永久堵塞

如何避免死锁:

​ 破坏四个必要条件中任意一个即可

创建线程:

1.继承Thread类

​ 1.创建Thread子类实现Thread类

​ 2.重写run方法

​ 3.创建线程对象,开启线程

package com.zql.demo02;

public class TestThread extends Thread {

    @Override
    public void run() {
        System.out.println("run正在执行");
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.start();
        System.out.println("main正在执行");
    }
}

2.实现Runnable接口

​ 1.定义类实现Runnable接口,重写run方法

​ 2.创建线程对象

​ 3.丢入线程对象,开启线程

package com.zql.demo02;

public class TestRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("run正在执行");
    }

    public static void main(String[] args) {
        TestRunnable testRunnable = new TestRunnable();
        new Thread(testRunnable).start();
        System.out.println("main正在执行");
    }
}

3.实现Callable接口

​ 1.创建实现类实现Callable接口,定义返回值类型

​ 2.new FutureTask创建线程对象

​ 3.丢入线程对象,调用start()开启线程

package com.zql.demo02;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("call执行");
        return 1;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<Integer> integerFutureTask = new FutureTask<>(new TestCallable());
        new Thread(integerFutureTask).start();

        Thread.sleep(1000);
        System.out.println("获得返回值:" + integerFutureTask.get());

        System.out.println("main执行");
    }
}

Runnable与Callable区别:

​ 相同点:

​ 1.都是接口

​ 2.都可以编写多线程程序

​ 3.都采用start()启动

​ 不同点:

​ 1.Runnable接口run方法没有返回值,Callable接口call方法有返回值,是个泛型

​ 2.Runnable接口run方法只能抛出运行时异常,无法捕获;Callable接口call方法可以抛出异常

Callable接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主程序运行

run()与start()有什么区别:

​ start()是用来启动线程的,run()只是一个函数

​ start()只可以调用一次,run()可以调用无数次

​ 调用start()启动线程,真正实现了多线程运行。

​ 直接调用run(),相当于调用一个普通函数

调用 start() 方法时会执行 run() 方法,为什么不直接调用 run() 方法?

new一个Thread,线程处于新建状态。调用start()方法,启动线程并且使该线程进入就绪状态,当cpu分配时间片就可以运行。自动调用run()。

直接调用run(),就是将run()作为一个普通方法执行,不是多线程。

调用start()会使线程进入就绪状态,调用run()只是thread中的一个普通方法。

常用方法:

1.通过外部标识位让线程停止 .stop()

package com.zql.demo02;

public class TestStop implements Runnable {

    //1.设置一个外部标识位
    private boolean flag = true;

    @Override
    public void run() {
        int j = 0;
        System.out.println("run执行---" + j++);
    }

    //2.设置一个停止方法
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {

        //3.创建线程对象
        TestStop testStop = new TestStop();
        //4.开启线程
        new Thread(testStop).start();
        //5.在规定下停止线程
        for (int i = 0; i < 50; i++) {
            System.out.println("main执行---" + i);
            if (i == 30){
                testStop.stop();
                System.out.println("线程停止");
            }
        }

    }
}

2.线程休眠 模拟倒计时

package com.zql.demo02;

public class TestSleep {

    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num <= 0){
                break;
            }
        }
    }
}

3.线程礼让 yield()

​ 礼让不一定成功,看CPU调度

package com.zql.demo02;

public class TestYield implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "---线程开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "---线程开始");
    }

    public static void main(String[] args) {
        TestYield testYield = new TestYield();
        new Thread(testYield,"thread1").start();
        new Thread(testYield,"thread2").start();
    }
}

4.强制执行 join()

package com.zql.demo02;

public class TestJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("run线程---" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        for (int i = 0; i < 100; i++) {
            if (i == 30){
                thread.join();
            }
            System.out.println("main线程---" + i);
        }
    }
}

线程池:

​ 线程池就是事先创建若干个可执行的线程放入到一个容器中,需要的时候从容器中获取,使用完不需要销毁,从而减少创建和销毁对象的开销。

使用工具类Executors生成一些常用的线程池:

​ 1.newSingleThreadExecutor 创建一个单线程的线程池

​ 2.newFixedThreadPool 创建固定大小的线程池

​ 3.newCachedThreadPool 创建一个可缓存的线程池

​ 4.newScheduledThreadPool 创建一个大小无限的线程池

package com.zql.demo02;

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

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

    public static void main(String[] args) {
        //创建线程池    参数为线程池大小
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        executorService.execute(new TestPool());
        executorService.execute(new TestPool());
        executorService.execute(new TestPool());
        executorService.execute(new TestPool());

        //关闭连接
        executorService.shutdown();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值