创建线程的方式
1)继承Thread类
2)实现Runnable接口
3)实现Callable接口(重写call方法,并把FutureTask对象传给Thread对象)(不常用)
start()方法和run()方法的区别
调用strat()方法才会体现多线程的特性,在不同线程的run方法里交替执行,执行run()方法可视为普通方法。
volatile关键字的作用
volatile修饰的变量保证其在线程之间可见。
如何在两个线程之间共享数据
线程之间共享对象。
sleep方法和weit方法的区别
两个方法都是释放CPU,
sleep()是Thread类的静态方法,它会使线程暂停执行一段时间,时间一到自动苏醒。
wait()是Object类的方法,直到其他线程用调用notify()或notifyAll()时才苏醒过来,开发人员也可以给它指定一个时间使其自动醒来。
sleep()不会释放锁,wait()会释放,从而使得线程所在对象中synchronized数据被别的线程使用。
wait()方法和notify()/notifyAll()方法在调用前都必须先获得对象的锁
写一个导致死锁的程序
1)两个线程里面分别持有两个Object对象:lock1和lock2。这两个lock作为同步代码块的锁;
2)线程1的run()方法中同步代码块先获取lock1的对象锁,Thread.sleep(xxx),然后接着获取lock2的对象锁。这么做主要是为了防止线程1启动一下子就连续获得了lock1和lock2两个对象的对象锁
3)线程2的run)(方法中同步代码块先获取lock2的对象锁,接着获取lock1的对象锁,当然这时lock1的对象锁已经被线程1锁持有,线程2肯定是要等待线程1释放lock1的对象锁的
为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object类里?
Java的每个对象中都有一个锁(monitor,也可以成为监视器) 并且wait(),notify()等方法用于等待对象的锁或者通知其他线程对象的监视器可用。在Java的线程中并没有可供任何对象使用的锁和同步器。这就是为什么这些方法是Object类的一部分,这样Java的每一个类都有用于线程间通信的基本方法。
wait():使调用该方法的线程释放锁,从运行状态退出,进入等待队列,直到被唤醒。
wait(long timeout):等待一段时间是否有线程唤醒锁,如果没有,超时自动唤醒。
notify():随机唤醒等待队列中的等待同一个锁的一个线程,使这个线程退出等待队列,进入可运行状态。
notifyAll():唤醒所有等待同样锁的所有线程,从等待队列中退出,进入可运行状态。
Condition接口常用方法
Condition 的 await,signal, singalAll 与 Object 的 wait, notify, notifyAll 都可以实现的需求,两者在使用上也是非常类似,都需要先获取某个锁之后才能调用,而不同的是 Object wait,notify 对应的是 synchronized 方式的锁,Condition await,singal 则对应的是 ReentrantLock (实现 Lock 接口的锁对象)对应的锁
await() :造成当前线程在接到信号或被中断之前一直处于等待状态
wait(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
signal() :唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
signal()All :唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。
为什么Thread类的sleep()和yield()方法是静态的
Thread类的sleep()和yield()方法将在当前正在执行的线程上运行。所以在其他处于等待状态的线程上调用这些方法是没有意义的。