并发原理:CPU分配时间片,多线程交替运行。宏观并行,微观串行。
Tread t=new Thread();表示新建一个线程对象,并不表示线程。
当调用t.start();才起动线程,当得到CPU时,就会执行线程t的方法体。
线程三要素:CPU、Date、Code
多线程间堆空间共享,栈空间独立。堆存的是地址,栈存的是变量(如:局部变量)
创建线程两种方式:继承Thread类或实现Runnable接口。
Thread对象代表一个线程。
多线程共同访问的同一个对象(临界资源),如果破坏了不可分割的操作(原子操作),就会造成数据不一致的情况。
在java中,任何对象都有一个互斥锁标记,用来分配给线程。
synchronized(o){..同步代码块. .}
对o(o是临界资源)加锁的同步代码块,只有拿到o的锁标记的线程,
才能进入对o加锁的同步代码块,退出同步代码块时,会自动释放o的锁标记。
synchronized的同步方法,如:public synchronized void fn(){} 对访问该方法的当前对象(this)加锁;哪个线程能拿到该对象(临界资源)的锁,哪个线程就能调用该对象(临界资源)的同步方法。
一个线程,可以同时拥有多个对象的锁标记
在java中,任何对象都有一个锁池,用来存放等待该对象锁标记的线程,
线程阻塞在对象锁池中时,不会释放其所拥有的其它对象的锁标记。
在java中,任何对象都有一个等待队列,用来存放线程,
线程t1对(让)o调用wait方法,必须放在对o加锁的同步代码块中!
1.t1会释放其所拥有的所有锁标记;
2.t1会进入o的等待队列
t2对(让)o调用notify/notifyAll方法,也必须放在对o加锁的同步代码块中!
会从o的等待队列中释放一个/全部线程,对t2毫无影响,t2继续执行。
当一个现成对象调用yield()方法时会马上交出执行权,回到可运行状态,等待OS 的再次调用
线程的生命周期
下面为线程中的7中非常重要的状态:(有的书上也只有认为前五种状态:而将“锁池”和“等待池”都看成
是“阻塞”状态的特殊情况:这种认识也是正确的,但是将“锁池”和“等待池”单独分离出来有利于对程序的理解)
1,初始状态,线程创建,线程对象调用start()方法。
2,可运行状态,也就是等待Cpu资源,等待运行的状态。
3,运行状态,获得了cpu资源,正在运行状态。
4,阻塞状态,也就是让出cpu资源,进入一种等待状态,而且不是可运行状态,有三种情况会进入阻塞状态。
1)如等待输入(输入设备进行处理,而CPU不处理),则放入阻塞,直到输入完毕,阻塞结束后会进入可运行状态。
2)线程休眠,线程对象调用sleep()方法,阻塞结束后会进入可运行状态。
3)线程对象2调用线程对象1的join()方法,那么线程对象2进入阻塞状态,直到线程对象1中止。
5,中止状态,也就是执行结束。
6,锁池状态
7,等待队列
课外问题:简述synchronized 和java.util.concurrent.locks.Lock的异同 ?
主要相同点:Lock 能完成synchronized 所实现的所有功能
主要不同点:Lock 有比synchronized 更精确的线程语义和更好的性能。synchronized 会自动释放锁,
而Lock 一定要求程序员手工释放,并且必须在finally 从句中释放。