多线程基础知识

线程

线程和进程的关系

进程就是一个可以独立运行的程序单位,它是线程集合,进程就是由一个或者多个线程构成的,而线程是进程中实际运行单位,是操作系统进行运算调度的最小单位。线程是进程中的一个最小运行单元。

并发和并行的区别?

 

 

并发是指程序同时进行,互不干扰,好比两个人同时用两把铁锹挖坑,一段时间后,会得到两个坑。

并行是指程序同一时间段同时进行,宏观上是两个程序同时运行,实则是程序在轮流使用cpu资源,只有正在使用资源的程序A才在运行,一段时间后,程序B拿到cpu使用权,则B开始运行,以此往复,看似同时,实则分时。就好比两个人拿一把铁锹挖两个坑。

线程创建的方式?

 通常使用的两种:

1.继承Thread类

     步骤1:定义一个类继承Thread

     步骤2:重写run方法

     步骤3:在main方法中创建子类对象,这个子类对象就是线程对象

     步骤4:调用start方法启动这个线程让线程执行,同时JVM去调用run方法

2.实现Runnable接口

     步骤1:定义一个类实现Runnable接口

     步骤2:实现接口中的抽象方法

     步骤3:在run方法中定义线程对象完成的任务

     步骤4:在main方法中,创建实现类对象,并把这个对象作为参数传递给Thread

     步骤5:调用Thread对象的start方法

线程的生命周期?

线程的生命周期分为五部分:新生状态、就绪状态、运行状态、阻塞状态、死亡状态。

当用户new完对象时,线程进入新生状态。当对象调用start方法时,线程进入就绪状态。线程调度分为分时调度和抢占式调度,java中使用的是抢占式调度了。当线程抢占到cpu资源时,线程进入运行状态。当调用方法打断线程时,线程进入阻塞状态。当线程运行完任务或者发生异常,又或者被调用stop方法时,线程进入死亡状态。

线程中常用的方法?

long getId() 返回此线程的标识符。

String getName() 返回此线程的名称。

int getPriority() 返回此线程的优先级

void run() 线程要完成任务

void start() 启动线程

void setName(String name) 将此线程的名称更改为等于参数 name

void setPriority(int newPriority) 更改此线程的优先级(1~10,默认为5级)。 

 

sleep(): 强迫一个线程睡眠N毫秒。

isAlive(): 判断一个线程是否存活。

join(): 等待线程终止。

activeCount(): 程序中活跃的线程数。

enumerate(): 枚举程序中的线程。

currentThread(): 得到当前线程。

isDaemon(): 一个线程是否为守护线程。

setDaemon(): 设置一个线程为守护线程(非守护线程全部终止后,它就会停止)。

setName(): 为线程设置一个名称。 Thread-0 Thread-1 Thread-2 ....

wait(): 强迫一个线程等待。

notify(): 通知一个线程继续运行。

setPriority(): 设置一个线程的优先级。

yield(): 释放手中的资源,但是依旧会和别的线程抢占

 

锁(同步线程)

锁的作用?

锁的作用其实就是为了保证线程的安全性。Java可以创建多个线程,在处理多线程问题时,必须注意这样的一个问题 ,当两个或者多个线程访问"同一个"变量,并且一个线程需要修改这个变量。应对这样的问题必须进行处理否则可能发生混乱。

比如:一个工资管理负责人正在修改员工的工资表,而一些员工也正在领取工资,如果允许这样操作,将出现问题。

在处理线程同步时,要做的第1件事情就是把修改数据的方法使用关键字 synchronized 来修饰,一个方法使用 synchronized 关键字修饰以后,当一个线程A使用这个方法的时候,其他线程想要使用这个方法则必须等待,直到线程A使用完这个方法。

设置锁的方法?

java中同步线程方法:

   1.使用Synchronized关键字修饰方法

      使用Synchronized关键字修饰的对象就相当于有了一把内置锁,调用被修饰的方法时会获得这把锁,其他的线程想要使用该方法,必须等内置锁释放,这样的方法就避免了两个线程同时使用公共资源的情况。但是由于每次进入都会产生内置锁,所以多个线程想要访问时必须排队等候,因此造成程序效率较低。

   2.使用有Synchronized修饰的语句块

      Synchronized(Object){

       }

       类似第一种方法,但是和第一种的区别是,它只将可能出现线程不安全的代码锁住,而不是锁住整个方法,一定程度上是对第一种方法的优化,提高了代码的执行效率。

   3.使用特殊域变量volatile

      volatile保证了不同线程对共享变量进行操作时的可见性,就是说当一个线程对一个变量的值进行了修改时,这个改变后的值对其他线程是立即可见的(因此在判断stop==!stop的情况下,在读取线程A两个值的过程中,线程B修改了stop的值,导致A出现判断stop==!stop为true的情况)

   4.使用Lock

      实际和第一种的情况一样,但是区别在于,这一种的钥匙比较明显。当我使用完后,可以通过调用Lock的unlock方法释放掉锁定锁。

   5.原子变量AtomicInteger

      为什么需要线程同步,原因普通变量的操作不是原子的。 什么是原子操作呢? 原子操作就是指读取变量值,修改变量值,保存变量值都看成一个整体 这些操作要么同时完成,要么同时不完成。原子性: 不可拆分。

 

死锁

什么是死锁?

死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

产生死锁的原因?

竞争资源引起进程死锁 。例如:线程A锁住左筷子并等待右筷子,线程B锁住右筷子并等待左筷子

这样两个线程就发生了死锁。

synchronized(左筷子){

      synchronized(右筷子){

       }

}

synchronized(右筷子){

        synchronized(左筷子){

        }

}

如何避免死锁?

如果我们能够避免在对象的同步方法中调用其它对象的同步方法,那么就可以避免死锁产生的可能 性。 尽量不要嵌套使用 synchronized 关键字。破坏任意一个,就可以解决死锁:

互斥使用:一个资源只能分配给一个线程

不可剥夺:资源只能由占有者释放,申请者不能强制剥夺

请求保持:线程申请资源时,保持对原有资源的占有

循环等待:存在一个进程等待队列:{P1 , P2 , , Pn}, 其中P1等待P2占有的资源,P2等待P3 占有的资源,…Pn等待P1占有的资源,形成一个进程等待环路



总结

一、多个线程对象在使用共享的资源对象时,需要使用同步。

线程同步:

1> 同步方法

public synchronized void m(){ //锁的是this,调用此方法的对象

 

}

public static synchronized void m(){ // 类名.class

}

2> 同步代码块

synchronized(对象){

//把可能产生线程安全的代码放入里面

}

二、 线程创建的方式?

方式1: 继承Thread

方式2: 实现Runnable接口

方式3: 实现Callable接口

方式4: 利用线程池创建

三、 同步有几种方式?

方式1:同步方法

方式2:同步代码块

方式3Lock 锁机制,lock()unlock()

方式4:利用阻塞队列

方式5ThreadLocal,将共享的资源,每一个线程都会拥有一个共享资源的副本,

每个线程都可以操作自己的那个副本,相互不影响

方式6:原子性操作类,AtomicInteger 等等

四、 启动线程是调用 start () 还是 run () ?

启动一个线程调用start(),再由JVM调用run()方法 ,run()只是定义线程的任务。

五、 sleep wait 的区别? " 都会从 running 运行状态 ---> block 阻塞 "

区别1sleepThread类静态方法 waitObject类非静态方法

区别2sleep不会释放对象锁,放弃CPU的使用权 ,在休眠时间内,不能唤醒,休眠时间一到,自动重新进入就绪状态。 wait方法会释放对象锁,wait方法只能使用 synchronized 方法或者代码块中使用,会放弃CPU的使用权, 若在同一对象的其他线程没有调用notify或者notifyAll 永远处于等待状态。

区别3sleep可以在任何地方使用wait只能在同步的代码块中使用

六、 死锁

如果线程A锁住了obj1并且等待obj2,而线程B锁住了obj2并且等待obj1,这样线程A和线程B就处于死锁状态。当线程任务出现了多个同步(同步嵌套)这样容易引用一种现象--死锁,程序无限等待。

七、 线程间通信 wait , notify , notifyAll

经典案例: 生产者 ---- 消费者

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值