------- android培训、java培训、期待与您交流! ----------
1.多线程的两种实现方式:
Thread有多个重构造方法,其中有两种最为常用,两种实现方式就是利用的这两个构造函数
Thread() 分配新的 Thread 对象。 |
Thread(Runnable target) 分配新的 Thread 对象。 |
1.1继承方式
1.定义一个新类C,并继承Thread类
2.在C中复写run方法
3.实例化一个C类对象,然后调用start方法,线程在运行完毕后会自动销毁。
这里详细介绍下c.run()和c.start()的区别(c是创建好的一个线程):
c.run()就是调用复写的run方法,跟普通的调用方法一样
c.start()是开启线程并执行run()方法。
1.2继承方式
1.定义一个新类C,并实现Runnable接口,复写run方法
2.实例化一个C对象p
3.实例化一个Thread对象,采用的是第二种构造方法,所以要将p作为参数传进去
4.调用start();
建议使用继承方式,以为Java只支持但继承,但支持多实现
2.线程的5种状态,主要是靠是否持有执行资格和执行权来分辨的
新建:start()
运行:具备执行资格,同时具备执行权;
冻结:sleep(time),wait()—notify()唤醒;线程释放了执行权,同时释放执行资格;
临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权;
消亡:stop() 或者自动销毁
3.“锁”的由来
没有锁的多线程是不安全的,举个例子:
4个窗口同时卖票,买票之前要设定好条件:票数大于0,当票数为1时,窗口1判断条件成立后就开始卖票,
在还未卖出之前窗口2也判断该条件,发现成立,然后俩个窗口都卖票,但是只剩下一张票了,程序就可能
卖出负数张票。
问题的原因:
当多条语句在操作同一个线程共享的数据时,一个线程对多条语句只执行了一部分,另一个线程就将操作权夺走
并执行语句,导致了共享数据的错误。
解决方法:
当一个线程执行多条语句时,在他未执行完时,其他线程不准执行,等于在线程进入一个房间操作时就在门上
挂把锁,操作完后再把锁打开。
3.1 挂“锁”的三种方式
挂锁的关键在于找准共享的数据,要把涉及到共享数据的代码锁起来,有三种方式:
1.同步代码块:
synchronized(obj)
{
//obj 表示同步监视器,是同一个同步对象
/**.....
TODO SOMETHING
*/
2.同步方法
格式:
在方法上加上synchronized 修饰符即可。 (一般不直接在 run 方法内,而是在它里面调用! )
synchronized 返回值类型 方法名(参数列表)
{
/**.....
TODO SOMETHING
*/
}
同步方法的同步监听器其实的是 this3.同步锁
jkd1.5 后的另一种同步机制:
通过显示定义同步锁对象来实现同步,这种机制,同步锁应该使用 Lock 对象充当。
在实现线程安全控制中,通常使用 ReentrantLock(可重入锁)。使用该对象可以显示地加锁和
解锁。
具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,
但功能更强大。
- public class X
- {
- //为了保证锁得唯一性,把锁的定义放在共享数据操作代码的外部,共享数据用try包裹
- private final ReentrantLock lock = new ReentrantLock();
- //定义需要保证线程安全的方法
- public void m(){
- //加锁
- lock.lock();
- try{
- //... method body
- }
- finally{
- //在 finally 释放锁
- lock.unlock();
- }
- }
- }
3.2死锁
死锁产生的原因是两把锁互相嵌套,两个线程各持自己的锁不放。
- public class sisuo {
- public static void main(String[] args) {
- Object A = new Object ();
- Object B = new Object ();
- Thread thread1 = new Thread(new sisuos(true));
- Thread thread2 = new Thread(new sisuos(false));
- thread1.start();
- thread2.start();
- }
- }
- <p>public class sisuos implements Runnable
- {</p><p> private boolean flag ;
- sisuos(boolean flag)
- {
- this.flag = flag;
- }
- public void run ()
- {
- while(true){
- if(flag)
- {
- synchronized (suo.A) {
- System.out.println(" 我有A锁");
- synchronized (suo.B) {
- System.out.println("我有AB锁");
- }
- }
- }
- else {
- synchronized (suo.B) {
- System.out.println(" 我有B锁");
- synchronized (suo.A) {
- System.out.println("我有AB锁");
- }
- }
- }
- }
- }
- }</p>
- <p>public class suo {</p><p> public static Object A = new Object ();
- public static Object B = new Object ();
- }</p>
4.线程间通讯
线程间通讯其实就是多个线程共同操作同一个共享资源,但是操作动作不同。
也就是多个实现了Runnabl接口不同的类,他们有不同的run方法
那么怎样保证他们是操作的是同一个共享资源呢?
1.构造方法从外部接受同一个资源
2.单例
4.1等待唤醒机制
为了使2个线程轮流操作,需要加入等待唤醒机制,他需要一个标志while(flag )
等待的方法:
锁.wait()
唤醒的方法
锁.notify()
需要注意的的是wait和notify的对象必须一致
但这样容易导致死锁(全部wait),所以用notifyAll
使用同步锁之后有另一种等待唤醒方法(推荐使用)
它提供了另一种监视器Condition,
Condition
将Object
监视器方法(wait
、notify
和notifyAll
)分解成截然不同的对象,以便通过将这些对象与任意Lock
实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock
替代了synchronized
方法和语句的使用,Condition
替代了 Object 监视器方法的使用。final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
他最大的好处在于可以定义多个监视器。
- //多线程的共享资源,要求有生产功能和销售功能,而且生产一个销售一个
- public class Resource {
- private boolean isHas = false;
- private int count = 0;
- ReentrantLock lock = new ReentrantLock();
- //通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
- Condition con_pro = lock.newCondition();
- Condition con_sale = lock.newCondition();
- public void product()
- {
- lock.lock();
- try
- {
- while(isHas)
- try {con_pro.await();} catch(Exception e){}
- System.out.println(Thread.currentThread().getName()+ "生产了商品"+ (++count));
- isHas = true;
- con_sale.signal();
- }
- finally
- {
- lock.unlock();
- }
- }
- public void Sale ()
- {
- lock.lock();
- try
- {
- while(!isHas)
- try {con_sale.await();} catch(Exception e){}
- System.out.println(Thread.currentThread().getName()+"出售了商品"+count);
- isHas = false;
- con_pro.signal();
- }
- finally
- {
- lock.unlock();
- }
- }
- }
- //生产线程
- public class Productor implements Runnable
- {
- private Resource resource ;
- public Productor(Resource resource) {
- this.resource = resource;
- }
- public void run()
- {
- while(true)
- {
- resource.product();
- }
- }}
- //销售线程
- public class Customer implements Runnable
- {
- private Resource resource ;
- public Customer(Resource resource) {
- this.resource = resource;
- }
- public void run()
- {
- while(true)
- {
- resource.Sale();
- }
- }
- }
- <p>public class sisuo {
- public static void main(String[] args) {
- Resource resource = new Resource();</p><p> //构造两个生产线程,两个销售线程
- new Thread (new Productor(resource)).start();
- new Thread (new Productor(resource)).start();
- new Thread (new Customer(resource)).start();
- new Thread (new Customer(resource)).start();
- }
- }</p>