#第一天 笔记 7/19

暑假开始学习java,今天开始每天都在这笔记做笔录做总结,希望能在目标的8月七号前完成第一遍的学习!加油!


1.使用关键字synchronized修饰的方式是不是表示让一个线程执行呢?事实并非如此,在Java语言中,每个对象都有一把“锁”,而关键字synchronized的意思是获取对象的锁。而这样的锁一次只能被一个线程获取,当多个线程执行syschronized操作的时候,其中一个线程抢到了“锁”,其他没有抢到的就等机会。当获取了锁的线程执行完毕,并释放“锁”之后,其他线程才能获取锁。


2.快捷键 整行删除  ctrl+d


3.

/*
 * 将售票的例子改成Runnable接口的方式
 * 
 * 创建线程方式2:
 * 1,定义一个类实现Runnable接口
 * 2,覆盖runnable接口中的run方法
 * 将线程要运行的代码存储到run方法中
 * 3,创建该接口的子类对象。
 * 4,通过Thread类进行线程的创建,并将Runnable接口的子类对象作为Thread类的构造函数的实参进行传递。
 * 为什么要传递?
 * 让线程对象创建时候,就要明确要运行哪个run方法,而这个run方法是需要被对象调用的。
 * 所以将run方法所属的对象传递给Thread类构造函数
 * 5,调用thread类中的start方式开启线程
 * 
 * Runnable接口的由来其实就是将线程的任务进行对象的封装
 * 将线程任务封装成对象后,通过Runnable接口可以降低和Thread对象的耦合性
 * 
 * 如果是集成Thread类,覆盖run方法这种情况
 * Thread的子类即封装了线程的任务,而且自身还是一个线程对象
 * 这就是任务和对象耦合性过高。
 * class Demo extends Thread{
 * public void run(){
 * //线程任务
 * }
 * }
 * Demo d = new Demo();//这是一个带有具备任务的线程对象
 * d.start();
 * 
 * 
 * 如果是实现Runnable接口
 * class Demo implements runnable{
 * public void run(){
 * //线程的任务
 * }
 * }
 * Demo d = new Demo();//这是一个任务对象
 * Thread t1 = new Thread(d);//创建线程对象去运行指定的任务。
 * 
 * class Thread{
 * Thread(Runnable r){
 * 
 * }
 * }
 * 
 * Runable接口的出现,线程对象在使用该接口
 * 我们只要实现该接口即可,讲实现的子类对象,也就是线程任务传递给线程对象就ok了
 * 
 * 以后创建线程就用Runnable接口的方式
 * 避免了单继承的局限性
 */



4.

/*
 * 通过两个线程来验证同步函数的锁是什么
 * 
 * 都是在买票一个在同步代码块中买票
 * 一个在同步函数中卖票。如果两个线程用的锁是同一个,就会同步,不会出现错票的情况
 * 
 * 同步函数使用的锁是什么呢?
 * 函数肯定被对象调用。代表调用函数对象的引用就是this。
 * 
 * 也就是说同步函数使用的锁是this
 * 
 * 
 * 
 * 同步函数与同步代码块的区别?
 * 1,同步函数函数比同步代码块写法简单
 * 2,同步函数使用的锁是this,同步代码块使用的锁是任意指定的对象
 * 建议开发时,使用同步代码块。尤其是需要不同锁时。
 * 
 * 
 * 静态同步函数使用的锁是什么?
 * 
 * 静态随着类的加载而加载的,这时内存中存储的对象至少有一个
 * 这就是该类字节码文件对象
 * 这个对象的表示方法 类名.class 他就表示字节码文件对象
 * 
 * 
 * 
 * 同步的另一个弊端:死锁。
 * 
 * 最常见的思索状况:同步嵌套
 * 同步中还有同步,两个同步用的不是一个锁
 * 记住尽量避免同步嵌套的情况
 * 
 */


5.suspend()方法和stop()方法容易导致死锁,不推荐




6.不要对死亡状态的线程调用start()方法,程序只能对新建状态的线程调用start()方法,对新建状态的线程两次调用start()方法也是错误的,这会引发IllegalThreadStateException异常



7.后台线程(aka守卫线程 aka精灵线程)特征:如果所有的前台线程都死亡,后台线程会自动死亡

调用Thread对象的setDaemon(true)方法可将制定线程设置为后台线程。可以看到 当所有前台线程死亡时,后台线程随之死亡。当整个学你急中只剩下后台线程时,程序就没有继续进行的必要了,所以虚拟机也就退出了


Thread类还提了isDaemon()方法,用于判断制定线程是否为后台线程


前台线程死亡后,JVM会通知后台线程死亡,但从他啊接受指令到做出相应,需要一定时间,而且要将某个线程设置为后台线程,必须在该线程启动之前设置。也就是说,setDaemon(true)必须在start()方法之前调用,否则会引发IllegalThreadStateException异常



8.

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。

synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。

随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:

     Lock l = ...; 
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }
 
锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。



9.ReentrantLock锁具有可重入性,也就是说,一个线程可以对已被加锁的ReentrantLock锁在此加锁,ReentrantLock对象会维持一个计算器来追踪lock()方法的嵌套调用,线程在每次调用lock()加锁后,必须显示调用unlock来释放锁,所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。





网上找到一个对锁机制的一个很好的解释  点击打开链接










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值