启动一个线程是调用run()还是start()方法?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM 调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。
线程的sleep()方法和yield()方法有什么区别?
1.sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
2.线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
3.sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
4.sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性
线程的6种状态?
1.new (初始化状态)
指的是在高级语言,比如java。在java层面的线程被创建了,而在操作系统中的线程其实还没有被创建,所以这个时候是不可能分配CPU执行这个线程!所以这个状态是高级语言独有的,操作系统的线程没这个状态。我们New了一个线程,那时候它就是这个状态。
2.Runnable (可运行/运行状态)
这个状态下是可以分配CPU执行的,在new()状态时候我们调用start()方法后线程就处于这个状态。
3.Blocked (阻塞状态)
这个状态下是不能分配CPU执行的,只有一种情况下会导致线程阻塞,就是synchronized!我们知道被Synchronized修饰的方法或者代码块同一时刻只有一个线程执行,而其他的竞争锁的线程就从Runnable到了Blocked状态,当某个线程竞争到了锁了他就变成了Runnable状态了。注意中Lock,是会让线程属于等待状态而不是阻塞,只有synchronized是阻塞。
4.Waiting (无时间限制的等待状态)
这个状态下也是不能分配CPU的执行的。有三种情况会使得Runnable状态到waiting状态
1.调用无参的object.wait()方法。等到notifyAll()或者notify()唤醒就会回到Runnable状态。
2.调用无参的Thread.join()方法。也就是比如你在主线程里面建立一个线程A,调用A.join(),那么你的 主线程是得等A执行完了才会继续执行,这是你的主线程就是等待状态。
3,调用LockSupport.park()方法。LockSupoort是java6引入的一个工具类java并发包中的锁都是基 于它实现的,再调用LockSupport.unpark(Thread thread),就会回到Runable状态。
5.Timed_Waiting (有时间限制的等待状态)
其实这个状态和waiting就是有没有超时时间的差别,这个状态下也是不能分配CPU执行的。有五种情况会使Runnable状态到waiting状态。
1.Object.wait(Long timeout)
2.Thread.join(long millis)
3.Thread.sleep(long millis)。注意:Thread.sleep(long millis,int nanos)内部调用的其实也是Thread.sleep(long millis).
4.LockSupport.parkNanos(Object blocked,long deadline)
5.LockSupport.parkUntil(long deadline)
6 Terminated(终止状态)
在我们的线程正常run结束之后或者run一半异常了就是终止状态!
Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复
wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。
什么叫做线程死锁,如何防止发生死锁?
所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。死锁产生的原因:系统资源的竞争;进程推进顺序非法;死锁产生的必要条件。
如何避免死锁
在有些情况下死锁是可以避免的。三种用于避免死锁的技术:
1.加锁顺序(线程按照一定的顺序加锁)
2.加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
解决方案:首先一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。