多线程(基础)

Posted ohana!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程(基础)相关的知识,希望对你有一定的参考价值。

目录

一,线程的概念

二,进程和线程的区别/联系

三,线程的创建

四,多线程的优势/作用

五,多线程的常用API

(1)activeCount

(2)run

(3)start

(4) currentTread

(5)getName

(6)sleep

(7) yield

(8)isAlive

(9) setDaemon

(10)isDaemon

(11) isInterrupt

(12)interrupt

(13) join

(14)join(可以理解为超时等待)

六,线程安全

(1)对于多个线程,操作同一个共享数据

(2)产生线程安全的原因

1.原子性

2.可见性

3.顺序性

七,解决线程不安全的问题

1.synchronized关键字

加锁方式

同步解释

底层原理

作用

2.volatile关键字

语法

作用

注意

适用场景

3.Lock

作用:

使用方式:

synchronized和Lock的区别:


一,线程的概念

Java中的线程,就是以轻量级的进程来实现的

二,进程和线程的区别/联系

(1)进程包含线程,一个进程至少包含一个线程

(2)进程是系统分配资源的最小单位(基本单位),线程是操作系统调度cpu执行的最小单位(基本单位)

(3)进程状态的改变会耗费很多的时间,线程相对来说更少

(4)进程占用独立的虚拟地址空间,同一个进程内的多个进程可以共享这个进程的内存

  •  一个进程要访问另一个进程的数据:需要使用通信的方式(代价比较大)
  • 同一个进程的线程,可以直接使用共享变量
  • 一个进程挂掉,不会影响其他进程,但是一个进程中的线程挂掉,就可能影响整个进程挂掉

(5)线程也具有进程的特征

  • 并发:一个CPU以时间片轮转调度算法,依次执行多个线程(肉眼感知同时进行)
  • 并行:多个cpu在一个时间点,同时执行多个线程

三,线程的创建

(1)继承Thread,重写run方法

public class MyThread 
    private static class myThread extends Thread
        @Override
        public void run() 
            System.out.println("my thread run!");
        
    
    public static void main(String[] args) 
        myThread thread = new myThread();
        thread.run();
    

(2)实现Runnable接口,重写run方法

public class MyRunnable 
    private static class myRunnable implements Runnable

        @Override
        public void run() 
            System.out.println("my runnable run!");
        
    
    public static void main(String[] args) 
        Thread thread = new Thread(new myRunnable());
        thread.run();
    

(3)实现Callable接口

实际上的常用写法:

public class MyThread 
    public static void main(String[] args) 
        Thread thread = new Thread(new Runnable() 
            @Override
            public void run() 
                System.out.println("线程启动了!");
            
        );
        thread.start();
    

四,多线程的优势/作用

(1)多个进程可以并发并行的执行,提高执行效率

(2)多线程技术使程序的响应速度更快 ,因为用户界面可以在进行其它工作的同时一直处于活动状态;

(3)当前没有进行处理的任务时可以将处理器时间让给其它任务;

(4)占用大量处理时间的任务可以定期将处理器时间让给其它任务;

(5)可以随时停止任务;

(6)可以分别设置各个任务的优先级以优化性能。

五,多线程的常用API

(1)activeCount

(返回当前进程处于活跃状态的线程数,线程创建好后,在销毁之前都是活跃态的)

(2)run

(定义线程需要执行的任务代码)

(3)start

(创建系统线程,并申请系统调度,转化为就绪态,如果调度到了,进入运行态,才会执行run方法的任务代码)

(4) currentTread

(返回这行代码执行时的当前线程引用对象)

(5)getName

(返回线程的名称)

(6)sleep

(让当前线程休眠???毫秒)

          (操作系统内部还有一个阻塞队列,线程休眠/阻塞,就是进入这个队列,等恢复(sleep就                 是等待一段时间)再拿出来执行)

(7) yield

(让当前线程让步,从运行态转为就绪态)

(8)isAlive

(线程引用对象是否是活跃状态)

(9) setDaemon

(设置某个线程为守护线程)

(10)isDaemon

(检测是否是守护线程,非守护线程就不会结束)

(11) isInterrupt

(返回线程内置的中断标志位)

(12)interrupt

(表示中断这个动作)

 

(13) join

(当前线程假如另一个线程,当前线程在这行代码等待,等另一个线程执行完,在执行后面的代码)

(14)join(可以理解为超时等待)

六,线程安全

(1)对于多个线程,操作同一个共享数据

(堆里面的对象,方法区中的数据,如静态变量)

  • 如果都是读操作,没有赋值操作,只是获取值——没有安全问题
  • 如果一个读,一个写
  • 多个写

只要有一个线程在进行写操作,就会存在线程安全问题

(2)产生线程安全的原因

1.原子性

(表示一组操作,可能是一行代码或者多行代码,是不可拆分的最小执行单位,就表示这组操作时原子性的)

2.可见性

(一个线程对共享变量值的修改,能够及时地被其他线程看到)

  • 线程之间的共享变量存在 主内存 (Main Memory).
  • 每一个线程都有自己的 "工作内存" (Working Memory) .
  • 当线程要读取一个共享变量的时候, 会先把变量从主内存拷贝到工作内存, 再从工作内存读取数据.
  • 当线程要修改一个共享变量的时候, 也会先修改工作内存中的副本, 再同步回主内存

由于每个线程有自己的工作内存, 这些工作内存中的内容相当于同一个共享变量的 "副本". 此时修改线程1 的工作内存中的值, 线程2 的工作内存不一定会及时变化

3.顺序性

也就是代码顺序,因为多线程具有并发并行的特征,代码执行的结果并不一定使我们想象的结果

七,解决线程不安全的问题

1.synchronized关键字

加锁方式

1) 直接修饰普通方法: 锁的 SynchronizedDemo 对象
2) 修饰静态方法: 锁的 SynchronizedDemo 类的对象
3) 修饰代码块: 明确指定锁哪个对象

同步解释

  • 使用对象来枷锁,多个线程需要先申请锁(synchronized自动申请)
  • 代码块结束(自动释放锁)
  • 多个线程只能有一个线程获取到同一个对象的锁

底层原理

  • 基于对象头加锁的方式,对象有对象头这一块区域,其中有一个字段标识是否加锁
  • 一个对象,同一个时间只能有一个线程获取到该对象的锁
  • jvm基于对象头加锁:monitor lock监视器锁
  • 本质上会使用到操作系统mutex lock锁来实现

作用

  •  保证了原子性,可见性,顺序性

2.volatile关键字

语法

  • 修饰一个变量

作用

  • 保证可见性,有序性

注意

  • 不保证原子性

适用场景

  • 读操作:读操作本身就是原子性的,所以使用volatile这行语句就是线程安全的
  • 写操作:赋值操作是一个常量值,也可以保证线程安全(写到主存)

3.Lock

Lock来源于juc包:java.util.concurrent包,这个包下的所有类,都是提供多线程并发编程用的,且满足线程安全,效率也很高

ReentrantLock这里的reentrant的意思就是可重入的

作用:

jdk提供锁的对象,专门用来加锁,达到线程安全的操作(synchronized的方式是自动加锁,释放锁,而Lock相当于是请了一个保安公司的保安来达到线程安全)

使用方式:

Lock lock = new ReentranLock();
try
    lock.lock();//锁对象加锁,只能有一个线程获取到锁
    ........//需要保证线程安全的代码
finally
     lock.unlock();//不管是否出现异常,都要释放锁

synchronized和Lock的区别:

1)从语法看,synchronized是自动加锁和释放锁,而Lock是显式(手动)来加锁释放锁;Lock更灵活,但要保证始终要释放锁(执行完不管是否出现异常)

2)Lock提供了更多获取锁的方式

3)从效率看,线程冲突比较严重的时候,lock性能要高很多

以上是关于多线程(基础)的主要内容,如果未能解决你的问题,请参考以下文章

java核心技术-多线程基础

多线程基础运用

python --- 基础多线程编程

多线程面试基础

多线程面试基础

多线程编程之基础概念