java基础-8.多线程

本文介绍了Java中的多线程概念,包括进程与线程的关系、为何使用多线程、CPU执行原理、并发与并行的区别、同步与异步的概念。详细讲解了通过继承Thread类、实现Runnable接口以及Callable接口创建线程的方法,并讨论了线程调度、线程安全问题及解决方案。
摘要由CSDN通过智能技术生成

基础-面向对象/语法/异常/常用api/数据类型/io/集合/多线程/高并发/

作者:虎啊兄弟 链接:https://zhuanlan.zhihu.com/p/65357630 来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

多线程

进程和线程

进程:正在执行的程序
线程:一条独立的执行路径
一个进程可以只有一条线程,也可以有多条线程
为什么要开启多线程?
1.执行某些耗时任务
2.希望某些程序看起来像同时执行
3.希望完成某个特定的子任务
4.防止线程阻塞
开启多线程是提高了效率吗?
不是,反而降低执行效率,但是提高了cpu的使用率
合理利用CPU的使用率
Java中开启了几个线程?
至少有两个1.主线程2.垃圾回收线程
多线程: 具有完成特定功能的执行路径,是CPU最先执行单位;CPU在某个时间刻度上只能够执行一条线程的一条原子性语句
int a = 1; 原子性a ++; 不是
a.将a的值读取出来b.将a的值+1
c.重新将新值赋值给System.out.println(a);

CPU的执行原理*

1.真实环境下,CPU能够同时执行多个程序,本质只是在同一个时间刻度上执行一条线程的一条原子性语句,只不过CPU切换执行速度非常快,我们无法察觉以为是同时执行

2.并发和并行

并发:在同一个时间段同时执行并行: 在同一个时间刻度上同时执行

**3.同步和异步

同步: 并发情况下会出现同步问题
异步:能够同一个时间段能够处理多个任务,例如ajax**
请求多线程和多进程的好处
1.多线程提高了进程的使用率,从而提高CPU的使用率
2.多进程提高了CPU的使用率

方式一:继承Thread类**(实例文末)

1.自定义类MyThread继承Thread类。
2.MyThread类里面重写run()方法。
3.创建线程对象。
4.启动线程。
**注意: **
1、启动线程使用的是start()方法而不是run()**方法
2、线程能不能多次启动

方式二:实现Runnable接口** (实例文末)

1.自定义类MyRunnable实现Runnable接口
2.重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,并把步骤3创建的对象作为构造参数传递
5.启动线程
实现接口方式的好处
可以避免由于Java单继承带来的局限性。
适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离, 较好的体现了面向对象的设计思想。
后面讲解线程同步的时候讲解方式

三:实现Callable方式开启线程实现**

Runnable和实现Callable接口的区别
1.有返回值
2.可以声明异常这里的返回值和异常抛出都是给到线程的启动者

方式四:匿名内部类开启线程**

方式五开启线程:**

Lambda表达式开启线程Lambda表达式是JDK1.8之后引入本质就是方便匿名内部类的书写函数式接口只有一个抽象方法的接口就是函数式接口
例如RunnableLambda表达式的语法
主要由三部分组成:
1.形参列表: 形式参数允许省略参数类型
2.箭头 ->
3.方法体:
由大括号包裹,当方法体中只有一条语句,{}可以省略当一个方法有返回值的时候,如果只是返回一条语句,那么return和{}都可以省略,这个表达式结果自动作为返回值的结果返回
如何设置和获取线程的名称设置和获取线程名称
通过构造方法 Thread(String name) 分配新的 Thread 对象。 Thread(Runnable target,String name) 分配新的 Thread 对象。 通过线程的成员方法 public final String getName() public final void setName(String name) 通过静态方法 public static Thread currentThread() 可以获取任意方法所在的线程名称,可以获取主线程的线程名称:Thread.currentThread().getName();long getId() 返回该线程的标识符。

线程调度*

Java是如何对线程进行调度的?
Java使用的是抢占式调度模型 抢占式调度模型 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。
设置和获取线程的优先级
public final int getPriority() public final void setPriority(int newPriority)
线程休眠 public static void sleep(long millis)
中断线程 public final void stop() public void interrupt()
线程加入 public final void join()
线程礼让 public static void yield() 让出CPU的执行权一小会 ,这里让出了CPU的执行权,并不是说把执行权交割了其他线程,而是释放了自己的执行权,自己还可以重新和其他线程抢夺执行权
后台线程 public final void setDaemon(boolean on)
一般来说,JVM(JAVA虚拟机)中一般会包括俩种线程,分别是用户线程和后台线程。
所谓
后台线程
(daemon)线程指的是:在程序运行的时候在后台提供的一种通用的服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束的时候,也就是用户线程都结束的时候,程序也就终止了。同时,会杀死进程中的所有的后台线程。
反过来说,只要有任何非后台线程还在运行,程序就不会结束。比如执行main()的就是一个非后台线程。

基于这个特点,当虚拟机中的用户线程全部退出运行时,守护线程没有服务的对象后,JVM也就退出了。

线程安全产生线程安全的因素:

1.必须存在多线程环境
2.至少有两条语句操作了共享数据
3.如果多个线程中有一个线程对共享数据进行了写操作
综合来说: 在多线程环境下,至少有两条以上的原子性语句操作了共享数据, 并且这个操作是写操作,肯定会出现线程安全问题

如何来解决线程安全问题?**

1.同步代码块
2.同步方法
3.Lock锁
1.同步代码块 格式: synchronized(锁对象){需要同步的代码;}
注意:
a.锁对象是任意对象 b.不同线程共享同一把锁 c.同步方法的锁对象是 this d.如果方法是静态方法,锁对象是字节码文件对象
同步的好处 :解决了多线程的安全问题。 同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的, 降低程序的运行效率。如果出现了同步嵌套,就容易产生死锁问题
2.同步方法 格式: public synchronized 返回值 方法名(参数列表) { //需要同步的代码块 }
3.Lock锁

实现一个线程的方式有两种:继承Thread类。实现Runnable接口

  1. Thread :
    (1)继承类
`package com.test;

public class ObjectThread extends Thread {
    private String name;
    public ObjectThread(String name) {
        super();
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程开始:" + this.name + ",i=" + i);
        }
    }
}`

(2)运行类

package com.test;

public class ThreadDome {
    public static void main(String[] args) throws CloneNotSupportedException {

//        ObjectThread mt1 = new ObjectThread ("线程a");
//        ObjectThread   mt2 = new ObjectThread ("线程b");
//        mt1.run();
//        mt2.run();
        ObjectThread  mt1=new ObjectThread ("线程a");
        ObjectThread mt2=new ObjectThread ("线程b");
        mt1.start();
        mt2.start();
    }
}

2.Runnable
(1)实现接口类

package com.test;

public class ObjectRunnable implements Runnable {
    private String name;
    public ObjectRunnable (String name) {
        super();
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程开始:" + this.name + ",i=" + i);
        }
    }
}

(2)运行类

package com.test;

public class RunnableDome {

    public static void main(String[] args) throws CloneNotSupportedException {

//        ObjectRunnable mt1 = new ObjectRunnable ("线程a");
//        ObjectRunnable mt2 = new ObjectRunnable ("线程b");
//        mt1.run();
//        mt2.run();
        ObjectRunnable mt1=new ObjectRunnable ("线程a");
        ObjectRunnable mt2=new ObjectRunnable ("线程b");
        new Thread(mt1).start();
        new Thread(mt2).start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值