Java多线程并发安全问题-总结

时间:2024-11-09 16:32:26

多线程

线程:单一的顺序执行流程就是一个线程,顺序执行:代码一句一句的先后执行。

多线程:多个线程并发执行。线程之间的代码是快速被CPU切换执行的,造成一种感官上"同时"执行的效果。

线程的创建方式
  1. 继承Thread,重写run方法,在run方法中定义线程要执行的任务

    优点:

    • 结构简单,便于匿名内部类创建

    缺点:

    • 继承冲突:由于java单继承,导致如果继承了线程就无法再继承其他类去复用方法
    • 耦合问题:线程与任务耦合在一起,不利于线程的重用。
  2. 实现Runnable接口单独定义线程任务

    优点:

    • 犹豫是实现接口,没有继承冲突问题
    • 线程与任务没有耦合关系,便于线程的重用

    缺点:

    • 创建复杂一些(其实也不能算缺点)
线程Thread类的常用方法

void run():线程本身有run方法,可以在第一种创建线程时重写该方法来定义线程任务。

void start():启动线程的方法。调用后线程被纳入到线程调度器中统一管理,并处于RUNNABLE状态,等待分配时间片开始并发运行。

      注:线程第一次获取时间片开始执行时会自动执行run方法。

              **启动线程一定是调用start方法,而不能调用run方法!**

String getName():获取线程名字

long getId():获取线程唯一标识

int getPriority():获取线程优先级,对应的是整数1-10

boolean isAlive():线程是否还活着

boolean isDaemon():是否为守护线程

boolean isInterrupted():是否被中断了

void setPriority(int priority):设置线程优先级,参数可以传入整数1-10。1为最低优先级,5为默认优先级,10为最高优先级

优先级越高的线程获取时间片的次数越多。可以使用Thread的常量MIN_PRIORITY,NORM_PRIORITY,MAX_PRIORITY。
他们分别表示最低,默认,最高优先级

static void sleep(long ms):静态方法sleep可以让运行该方法的线程阻塞参数ms指定的毫秒。

static Thread currentThread():获取运行该方法的线程。

void setDaemon(boolean on):设置线程是否为守护线程,当参数为true时当前线程被设置为守护线程。该操作必须在线程启动前进行

守护线程与普通线程的区别主要体现在当java进程中所有的普通线程都结束时进程会结束,在结束前会杀死所有还在运行的守护线程。

重点:多线程并发安全问题
  • 什么是多线程并发安全问题:

    当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致执行顺序出现混乱。

    解决办法:

    将并发操作改为同步操作就可有效的解决多线程并发安全问题

  • 同步与异步的概念:同步和异步都是说的多线程的执行方式。

    多线程各自执行各自的就是异步执行,而多线程执行出现了先后顺序进行就是同步执行

  • synchronized的两种用法

    xxxxxxxxxx package thread;​/** * 守护线程 * 线程提供了一个方法: * void setDaemon(boolean on) * 如果参数为true,则会将当前线程设置为守护线程。 * * 守护线程与普通的用户线程(线程创建出来时默认就是用户线程)的区别在于进程结束 * * 进程结束: * 当一个JAVA进程中所有的用户线程都结束时,进程就会结束,此时会强制杀死所有还在运行 * 的守护线程。 * * GC就是运行在一条守护线程上的。 */public class DaemonThreadDemo { public static void main(String[] args) { Thread rose = new Thread(“rose”){ public void run(){ for(int i=0;i<5;i++){ System.out.println(getName()+“:let me go !!!”); try { Thread.sleep(1000); } catch (InterruptedException e) { } } System.out.println(getName()+“:啊啊啊啊啊AAAAAAaaaaa…”); System.out.println(“噗通!”); } };​ Thread jack = new Thread(“jack”){ public void run(){ while(true){ System.out.println(getName()+“:you jump!i jump!”); try { Thread.sleep(1000); } catch (InterruptedException e) { } } } };​ rose.start(); jack.setDaemon(true);//设置守护线程必须在线程启动前进行 jack.start();​​ }}java

    2.同步块,推荐使用。同步块可以更准确的控制需要同步执行的代码片段。

    有效的缩小同步范围可以在保证并发安全的前提下提高并发效率

  • 同步监视器对象的选取:

    对于同步的成员方法而言,同步监视器对象不可指定,只能是this

    对于同步的静态方法而言,同步监视器对象也不可指定,只能是类对象

    对于同步块而言,需要自行指定同步监视器对象,选取原则:

    1.必须是引用类型

    2.多个需要同步执行该同步块的线程看到的该对象必须是同一个

  • 互斥性

    当使用多个synchronized修饰了多个代码片段,并且指定的同步监视器都是同一个对象时,这些代码片段就是互斥的,多个线程不能同时在这些代码片段上执行。