多线程实现方式(两种方式的区别)
- 查看源码的区别:
- a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
- b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法
- 继承Thread
- 好处是:可以直接使用Thread类中的方法,代码简单
- 弊端是:如果已经有了父类,就不能用这种方法
- 实现Runnable接口
- 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
- 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
还有一种实现方式,就是实现Callable接口,代码复杂,很少用
多线程同步之Synchronized锁对象
- 非静态同步方法的锁对象是this
- 静态同步路方法的锁对象是该类的字节码对象(XX.class)
- 同步代码块的锁对象不能是匿名对象,因为匿名对象不是同一个对象,其他任意对象都可以
- 在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
多线程同步之ReentrantLock
- 1.同步
- 使用ReentrantLock类的lock()和unlock()方法进行同步
- 2.通信
- 使用ReentrantLock类的newCondition()方法可以获取Condition对象
- 需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
- 不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了
sleep(long millis)和wait()区别
- sleep方法必须传入时间参数,时间到了,自动醒来;wait方法可以传参也可不传参数,传参数表示在参数时间结束后等待,不传入参数就是直接等待
- sleep方法在同步方法或同步代码块中,不释放锁(睡着了也要抱着锁);而wait方法释放锁
- sleep是Thread类的静态方法,而wait方法只能使用锁对象来调用