多线程

线程分为用户线程和守护线程

 

线程的五大状态:创建~就绪~阻塞~运行~死亡

 

 

多线程创建方式

1、继承Thread类,重写run方法

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

3、实现Callable接口,重写call方法,创建执行服务,提交执行,获取结果,关闭服务(优势:可以定义返回值,可以抛出异常)

 

线程停止:

1、不推荐使用JDK提供的stop()、destroy()方法【已废弃】

2、推荐线程自己停下来(正常停止)———> 利用次数,不建议死循环

3、建议使用一个标识进行终止        如:当变量值为false,则停止线程运行

 

线程休眠:

1、sleep指定当前线程阻塞的毫秒数

2、sleep存在异常需要捕获或抛出

3、sleep时间达到后进入就绪状态

4、sleep可以模拟网络延时,倒计时等

5、每一个对象都有一个锁,sleep不会释放锁

 

线程礼让:

1、让当前正在执行的线程暂停但不阻塞

2、将线程从运行状态转为就绪状态

3、让CPU重新调度,礼让不一定成功

 

线程强制执行:join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞,可以理解为插队

 

线程优先级:

1、java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行

2、线程优先级用数字表示,范围从1~10,默认优先级为5

1)Thread.MIN_PRIORITY=1

2)Thread.MAX_PRIORITY=10

3)Thread.NORM_PRIORITY=5

3、使用以下方式改变或获取优先级

getPriority()//获取优先级

setPriority(int xxx)//设置优先级

4、优先级的设定建议在start()调度前

5、优先级低只是意味着被调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度

 

守护(daemon)线程:

1、虚拟机必须确保用户线程执行完毕

2、虚拟机不用等待守护线程执行完毕

3、如:后台记录操作日志,监控内存,垃圾回收等待......

setDaemon(true)//修改为守护线程,默认是false表示用户线程

 

线程同步:

1、处理多线程问题时,多个线程访问同一个对象(并发),并且某些线程还想修改这个对象,这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用

2、为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,使用后释放锁即可,存在以下问题:

1)一个线程持有锁会导致其他所有需要此锁的线程挂起

2)在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题

3)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题

 

同步方法:

synchronized方法控制对对象的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

缺陷:若将一个大的方法申明为synchronized将会影响效率

 

同步块:synchronized(Obj){ }

1、Obj称之为同步监视器

1)Obj可以是任何对象,但是推荐使用共享资源作为同步监视器

2)同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class

2、同步监视器的执行过程

1)第一个线程访问,锁定同步监视器,执行其中代码

2)第二个线程访问,发现同步监视器被锁定,无法访问

3)第一个线程访问完毕,解锁同步监视器

4)第二个线程访问,发现同步监视器没有锁,然后锁定并访问

 

死锁:

1、多个线程各自占有一些共享资源,并且互相等待其他线程的资源才能运行,从而导致两个或多个线程都在等待对方释放资源,某一同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”问题

2、下面列出了死锁产生的四个必要条件,我们只需要想办法破其中任意一个或多个条件就可以避免死锁发生

3、产生死锁的四个必要条件:

1)互斥请求:一个资源每次只能被一个进程使用

2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放

3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺

4)循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系

 

Lock(锁):

 

synchronized与Lock的对比:

1、Lock是显示锁(需手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放

2、Lock只有代码块锁,synchronized有代码块锁和方法锁

3、Lock锁性能更好,且具有更好的扩展性,能提供更多的子类

4、优先使用顺序:Lock  >  同步代码块(已经进入了方法体,分配了相应资源)>  同步方法(在方法体之外) 

 

线程池:

1、背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大

2、思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。

3好处:

1)提高响应速度(减少了创建新线程的时间)

2)降低资源消耗(重复利用线程池线程,不需要每次都创建)

3)便于线程管理

posted @ 2021-09-22 17:08  吃饭睡觉娶岳梅  阅读(18)  评论(0)    收藏  举报