ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022-08-03 day21 第一小组 王鸣赫

2022-08-03 22:01:11  阅读:187  来源: 互联网

标签:03 synchronized 对象 08 day21 死锁 线程 进程 偏向


目录

多线程

1.synchronized 的使用

1.1概述

为了解决线程安全的问题,使用了synchronized 进行加锁的操作。
同步机制synchronized:synchronized关键字用于修饰方法或者单独的synchronized代码块,当一个线程想执行synchronized中的内容时,必须先获取到对象锁,当对象锁没有线程占用时,进入synchronized方法会自动获取到对象锁,执行完毕后会自动释放锁,如果对象锁被A线程占用,B线程想执行synchronized的代码只能等待A线程执行完毕后,释放对象锁,B线程才能获取到对象锁进入方法执行。一个线程获得对象A的锁,也可以获得对象B的锁,两个不同类的对象锁没有关联。

1.2 方法锁

synchronized 方法控制对类成员变量的访问:  
 每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。

1.3 对象锁(synchronized修饰方法或代码块)

当一个对象中有synchronized method或synchronized block的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁。如果此对象的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也是对象锁)

点击查看代码
public class Test
{
    // 对象锁:形式1(方法锁)
    public synchronized void Method1()
    {
        System.out.println("我是对象锁也是方法锁");
        try
        {
            Thread.sleep(500);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
 }
// 对象锁:形式2(代码块形式)
public void Method2()
{
    synchronized (this)
    {
        System.out.println("我是对象锁");
        try
        {
            Thread.sleep(500);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

}
1.4 类锁(synchronized 修饰静态的方法或代码块)

由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只有一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。

点击查看代码
public class Test
{
   // 类锁:形式1
    public static synchronized void Method1()
    {
        System.out.println("我是类锁一号");
        try
        {
            Thread.sleep(500);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    // 类锁:形式2
    public void Method2()
    {
        synchronized (Test.class)
        {
            System.out.println("我是类锁二号");
            try
            {
                Thread.sleep(500);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }

        }
    }
}
1.5 局限性

Synchronized它锁定一个对象,可以加锁到方法上,亦可加锁到一段代码上。它加锁到一段代码上,代表了对这段代码中的共享对象/资源进行单独运行;Lock通过方法lock(),unlock()来进行锁定。

Synchronized有局限性:

它不可中断,一旦开始执行,一定要等执行结束后才能释放。对于正在申请锁的行为,只能死等。
不能向tryLock()一样设定超时时间。
只有一个条件,不能像Condition那样可以设置多个。
Synchronize是可重入锁(Reentrance Lock),不可中断; Lock接口有一个ReentranceLock的实现类,可以实现Synchronized的功能,但更加灵活,在极端情况下性能会更好一些。

2.死锁

2.1死锁的定义

所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

2.2死锁产生的原因
1) 系统资源的竞争

通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。

2) 进程推进顺序非法

进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。

3)信号量使用不当也会造成死锁。

进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。

4) 死锁产生的必要条件

产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。
互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有。

无锁 、 偏向锁、量级锁 和 重量级锁
(1)无锁

无锁没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功
CAS原理及应用即是无锁的实现。无锁无法全面代替有锁,但无锁在某些场合下的性能是非常高的。

(2)偏向锁

偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价。
偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动释放偏向锁。偏向锁的撤销,需要等待全局安全点(在这个时间点上没有字节码正在执行),它会首先暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态。撤销偏向锁后恢复到无锁(标志位为“01”)或轻量级锁(标志位为“00”)的状态。

偏向锁在JDK 6及以后的JVM里是默认启用的。可以通过JVM参数关闭偏向锁:-XX:-UseBiasedLocking=false,关闭之后程序默认会进入轻量级锁状态。

(3)轻量级锁

是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

若当前只有一个等待线程,则该线程通过自旋进行等待。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。

(4)重量级锁

升级为重量级锁时,锁标志的状态值变为“10”,此时Mark Word中存储的是指向重量级锁的指针,此时等待锁的线程都会进入阻塞状态。

重入锁

可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁

点击查看代码
public synchronized void operation(){
    add();
}

public synchronized void add(){

}
线程的常用方法
  • Thread类中的方法
  • 1.start:启动当前线程;执行run方法
  • 2.run:
  • 3.currentThread:静态方法,获取当前正在执行的线程
  • 4.getId():返回此线程的唯一标识
  • 5.setName(String):设置当前线程的name
  • 6.getName():获取当前线程的name
  • 7.getPriority():获取当前线程的优先级
  • 8.setPriority(int):设置当前线程的优先级
  • 9.getState():获取当前线程的声明周期
  • 10.interrupt():中断线程的执行
  • 11.interrupted():查看当前线程是否中断

标签:03,synchronized,对象,08,day21,死锁,线程,进程,偏向
来源: https://www.cnblogs.com/wmh19990109/p/16548821.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有