Java基础_初识多线程

多线程

在之前写的代码中,都是只有一条路径,从main方法开始走,顺序执行。而多线程相当于开辟了多条道路。不一定只在main方法这条路上跑。其他操作可以在其他道路上进行。如同一条道路容易发生堵车。但是多条道路,就不容易,并且效率也提高了。####

概念

程序——java运行文件,或者一个exe文件都是软件。

进程——正在执行的程序被称为进程(进行中的程序)。

	进程是程序动态执行一次的过程,占用特定的地址。进程由3部分组成,cup,data,code。每个进程
	相互独立。操作系统在多任务下,将时间动态的划分给每个进程,对进程来说独占时间,对于使用者来
	说是多任务同时执行。

线程——线程是进行中的一个单一控制路径。线程之间可以达到数据共享。被称为轻量级进程

	一个进程在同一时间可以有多个并行的线程。一个进程中的线程共享相同的内存单元/地址空间,可以
	**访问相同的变量和对象**。而且他们从同一个堆中分配对象通信,数据交换。并且因为在同一个单元
	进行操作,他们之间的通信没有限制,因此信息传递速度更加高效

在这里插入图片描述cpu分配是按线程来分配的。内存是按进程分配的,并且每个线程有自己的栈,用来存储变量。而堆是共享的
在一个cpu情况下多线程都是模拟出来的,同一时间cpu只给一条线程分配时间片,只执行一段代码,因为切换很快。毫秒级因此感觉上是多线程。(并发编程——一个时间段多个线程)
在多核cpu下才是多线程。(并行编程——同一时间点多个线程)

多线程的优点

资源利用率更好;
程序设计在某些情况下更简单;
程序响应更快

缺点
大多数情况下,比单线程设计更复杂。线程之间的交互也非常复杂。不正确的线程同步会造成莫名的错误并且难以被重现

上下文切换的开销。当CPU 从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的 数据,程序 指针等,然后载入另一个线程的本地数据,程序指针 等,最后才开始执行。这种切换并不简单,会耗费效率。尽量减少这种切换。

线程的基本操作
1、创建线程
2、阻塞线程
3、停止线程
4、锁
5、当前线程的一些操作

创建线程

1、通过继承Thread
创建:继承Thread,并且重写run方法
通过new 对象 调用.strat()方法来启动线程。


public class MyThread1 extends  Thread{   
    @Override
    public void run() {
        System.out.println("running");
    }
     public static void main(String[] args) { 
     MyThread1 thread1 = new MyThread1(); //创建线程类。
     thread1.satrt();   //启动线程 
     }
}

缺点:单继承,不能再去继承别的类。
2、通过实现Runnable接口
创建:
1、类实现Runnable接口,实现run方法。
2、Runnable是函数式接口,可以通过lambda或者匿名内部类。
加载:
类对象通过Thread的构造器传入。一样通过.start()启动。

new Thread(()->{    //lambda的形式
            System.out.println("ddddd");
        }).start(); //简写
Thread thread2 = Thread(new Runnable(){ //通过内部类形式。
            @Override
            public void run() {
                System.out.println("ddd");
            }
        });
        thread2.start();

缺点:不能有返回值,也不能抛出异常。但是返回值可以通过外部变量存储来解决。
3、通过实现Callable接口
创建
1、通过实现Callable接口,实现call方法。需要一个返回值
2、作为FutureTask<>类的方法传入。泛型中定义返回值类型。
3、通过Thread去启动线程
4、通过FutureTask类的实例对象的get方法去获取返回值。

FutureTask<String> s = new FutureTask<>(new Callable<String>() { //定义FutureTask类
            @Override
            public String call() throws Exception {  //重写call方法
                return "sssss";
            }
        });
new Thread(s).start();  //启动线程
 System.out.println(s.get()); //通过get方法获取值
线程的5种状态

1、新生状态——start()调用。启动线程就进入线程的新生
2、就绪状态——strat调用后,准备工作完成即就绪状态,或者运行状态的cpu时间片到了退回到就绪状态
3、运行状态——进行操作的状态
4、阻塞状态——io资源被占用,sleep和wait方法人为停止(唤醒可以解除阻塞)。或者其他资源被抢占。
5、结束状态——自然结束,线程方法执行完毕,或者人为调用stop 和destroy方法。
在这里插入图片描述结束线程一般通过线程自己结束或者外部干涉。通过标识去终止 如设定退出循环条件等等。

阻塞线程

处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待io设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。被阻塞的线程不能进入就绪状态,只有阻塞的原因接触了才能进入。

有三种方式暂停Thread的执行
1、sleep方法:阻塞当前线程,并且别的线程也不能访问锁定的对象。参数为暂停的毫秒数

	sleep可以用在任何地方,是Thread的静态方法。在sleep过程中,如果别的对象调用到了sleep所在线程的
	interrupt方法则会产生异常。它只对当前线程有用,使用对象.sleep方法是不行的。

在这里插入图片描述
2、yield方法:让出CPU的使用权,从运行态直接进入就绪态。让CPU重新挑选哪一个线程进入运行状态。

	如果此时是单线程,那么yield方法则不产生作用

3、join方法:暂停当前线程,等待调用join方法的线程执行完再继续当前线程。
在这里插入图片描述4、wait()方法:暂停当前线程,并释放资源。等待唤醒,如果不唤醒将永远等待。但是可以使用线程的interrupt()方法去强制停止线程。会产生异常。但是通过trychach处理可以安全退出。

	必须再synchronized块或函数中使用。如果再非synchronized块或函数中使用虽然编译能通过,但是执行会
	产生illegalMonitorStateException的异常
线程的基本方法
  • isAlive——判断当前线程是否还存在
  • getPriority()——获取当前线程的优先级 默认为5,最高10,最小1
  • setPriority()——设置当前线程的优先级
  • setName()——设置线程的名称
  • getName()——获取线程的名称
  • currentThread()——取得当前正在运行的线程。自己本身。

优先级只代表调度的概率。是否真的调度看cpu

Thread th = new Thread(()->{
	System.out.println("aaaaa");
});
th.getName(); //获取名称
th.setName("线程1"); //设置名称
th.isAlive();//是否还存在,返回Boolean
th.getPriority(); //获取优先级
th.setPriority(10);//设置优先级
Thread.currentThread().getName();//获取当前线程的名称
同步

多线程操作数据,会使得数据产生访问冲突问题。java中提供了同步机制解决这种问题。
synchronized
synchronized 方法和 synchronized 块

1、synchronized方法:通过在方法声明中加入synchronized来声明此方法为同步方法
如: public synchronized void vvv();

	普通同步方法,锁是当前实例对象 ,进入同步代码前要获得当前实例的锁。被锁定后,其他线程不能
	再操作该对象的synchronized方法。
	静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁
	不是同步方法則不需要鎖就能访问

2、2. synchronized 块:通过 synchronized关键字来声明synchronized 块

	同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码前要获得给定对象的锁。
synchronized(锁的对象){
//操作
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值