线程和进程的区别
1. 线程共享相同的数据,线程间通信更加的容易,而进程都有自己的数据。
2. 线程更加的轻量级,创建和销毁单个线程比发起进程开销要小的多。
3.
线程状态(包含线程同步的情况)
中断:线程运行过程中,因为某个原因被暂停运行,目的是使其它线程获得运行的机会。
如果一个线程被阻塞就无法检查其中断状态
线程的属性
线程优先级:线程默认情况下继承父线程的优先级。
守护线程:惟一责任是为其它线程服务,当只剩下守护线程了JVM就退出了。
线程组
作用:同时对一组线程进行操作。
步1:创建:ThreadGroup g=new ThreadGroup(”groupName”);
步2:添加:Thread t=new Thread(g,threadName);
线程的未检查异常处理
作用:处理run()方法中的未检查异常
处理器必须实现Thread.UncaughtExceptionHandler接口。
接口只有一个方法,uncaughtException(Thread t, Throwable e) 出现未检查异常时调用。
此方法执行的具体步骤如下:
1. 如果该线程组还有父线程组,则调用父线程组的uncaughtException()方法。
2. 否则,如果此方法返回一个非null处理器,则调用该处理器。
3. 否则,如果Throwable是一个ThreadDeath实例,则什么都不做。
4. 否则,线程的名字和Throwable的堆栈踪迹将被输出到System.err上。
5.
线程的创建方法
方法1:推荐使用 | |
步1:实现Runnable接口,并在run()方法中定义要做的事情。 | class MyRunnable implments Runnable{ public void run(){do something;} } |
步2:创建一个MyRunnable类 | Runnable mr=new MyRunnable(); |
步3:由Runnable构造一个Thread对象 | Thread t=new Thread(mr); |
步4:启动一个线程 | t.start(); |
方法2: | |
步1:直接继承Thread类,覆盖run()方法 | Class MyThread extends Thread{ public void run(){do something;} } |
步2:创建一个MyThread类的对象 | Thread t=new MyThread(); |
步3:启动一个线程 | t.start(); |
线程的并行运行(重要)
当多个线程并行运行并且都要访问临界资源时,由于条件竞争,会产生数据腐蚀现象,还会产生死锁现象.
解决多线程并行运行所产生的问题的方法
1. 同步锁机制 采用JDK5.0引进的ReentrantLock类,功能比2强大
2. 同步锁机制 采用Synchronized关键字
3. 阻塞队列 4种 继承自java.util.current.BlockingQueue接口
4. 同步队列 1种 继承自java.util.current.BlockingQueue接口
5. 同步器 如:障栅 倒计时门 同步队列 信号量
提高线程组访问效率和管理效率:
1. 执行器 包含了线程池的使用
同步的建议
1. 正确的使用同步可以保证其它任何方法都不会看到对象处于不一致的状态中。
2. 正确的使用同步可以保证对象从一种一致的状态转变到另一种一致的状态。
3. 为了在线程之间可靠的通信,以及为了互斥访问,同步是需要的。
4. 对可变共享数据,特别是作用在它们上面的写操作,一定要加同步。
5. 一般双重检查模式并不能正确的工作,除非共享变量是原语值而不是引用值。
6. 同步区域应该做尽可能少的动作,同步过多增加死锁降低性能。
7. 避免使用线程组
8. 总是在while循环模式来调用wait()
Synchronized (obj){
while(condition does not hold){obj.wait()…}
}
9. 对访问共享变量的所有方法都要考虑是否加锁,因为若有的不加锁可造成数据错误
对象的锁机制
1. 每个对象都有一个互斥锁(隐式锁),且每个锁都有一个隐式条件,且这个锁在一个时间点上只可以分配给满足条件的一个线程。
2. 有两种获得对象锁的途径,通过调用一个同步方法或调用一个同步块。
3. 锁是可重入的,一个线程获得了锁,它可以再次获得,同时会增加锁的持有计数。
4. 锁是递归的,可嵌套的
5.一个锁对象可以有一个或多个相关联的条件对象。
同步锁机制 采用ReentrantLock类
ReentrantLock和Synchornized有同样的语意,但是它的功能强大些。
ReentrantLock可以有多个条件对象即Condition对象,利用条件对象作为控制条件。
ReentrantLock 的使用 | ||
1 | Lock myLock=New ReetrantLock(); | //创建一个锁对象 |
Lock fairLock=New ReetrantLock(true); | //创建一个公平锁对象 | |
Condition myCondition; | //创建一个条件对象 | |
2 | myLock.lock(); | //获取锁,可能阻塞 |
myLock.tryLock(); | //试图获得锁,不阻塞 | |
myLock.tryLock(100,TimeUnit.MILLISECONDS); | //为tryLock设置锁超时 | |
3 | myCondition= myLock.newCondition(); | //获得锁的条件对象 |
4 | while(等待条件成立){myCondition.await()}; | //等待条件成立时等待 |
5 | myCondition.singalAll(); myCondition.singal(); | //激活等待线程 |
6 | myLock.unlock(); | //释放锁 |
注 | tryLock()若没有获得锁,则其可以不阻塞而去干别的事。 tryLock()若调用时获得锁则立即获得锁,而不管是否有线程已经等待了很久。 tryLock(,)若在等待时被中断,将抛出InterruptException异常,可以打破死锁 await()在被激活、到达超时、被中断时await()将返回。 await()在等待时被中断将抛出InterruptException异常。 | |
| java.util.current.locks.Lock java.util.current.locks.ReetrantLock java.util.current.locks.ReetrantReadWriteLock java.util.current.locks.Condition |
Synchronized 进行同步 |
synchronized给方法加锁,作用域为一个方法。 |
public synchronized method()throws InterruptedException{ while(condition){wait();} //等待 ...... notifyAll();//notify() 激活其它等待线程 } |
synchronized给对象加锁,作用域为整个对象。 |
synchronized(object){ while(condition){wait();} //等待 ...... notifyAll();//notify() 激活其它等待线程 } |
注:隐式锁只有一个条件。 |
阻塞队列 | ||
1 | ArrayBlockingQueue | 循环数组实现,可指定容量和公平性。 |
2 | LinkedBlockingQueue | 链表实现,可指定容量。 |
3 | PriorityBlockingQueue | 堆实现,无限的阻塞优先级队列。 |
4 | DelayQueue | 无界的,阻塞时间有限的阻塞队列,实现了Delay接口。
|
阻塞队列:其实就是为了解决生产者消费者问题由JDK提供的队列。
阻塞队列操作 | ||
方法 | 动作 | 失败时动作 |
add | 增加一个元素 | 若队列满,则抛异常 |
remove | 移出并返回头部元素 | 若队列空,则抛异常 |
element | 返回队列头部元素 | 若队列空,则抛异常 |
offer | 添加一个元素并返回true | 若队列满,返回false |
poll | 移出并返回头部元素 | 若队列空,返回null |
peek | 返回队列头部元素 | 若队列空,返回null |
put | 添加一个元素 | 若队列满,阻塞 |
take | 移出并返回头部元素 | 若队列空,阻塞 |
死锁
优化:把锁的粒度加粗,不要握有多个锁。
API | |
Thread.currentThread() | 静态方法,获得当前线程 |
Thread.currentThread().isInterrupted() | 实例方法,检查是否有线程已被中断,不会改变中断状态。 |
Thread.isAlive() | 实例方法,测试线程是否处于活动状态。 |
Thread.isDaemon() | 实例方法,测试该线程是否为守护线程。 |
Thread. getThreadGroup() | 实例方法,返回该线程所属的线程组。 |
Thread.interrupt() | 中断线程 |
Thread.currentThread().interrupted() | 静态方法,检查当前线程是否被中断,若是则清除其中断状态。 会打断线程的睡眠状态 |
Thread.sleep() | 静态方法,中断当前正在执行的线程,且不释放对象的锁标记。 |
Thread.yield() | 静态方法,中断当前正在执行的线程。 |
Thread.dumpStack() | 静态方法,打印当前线程的堆栈跟踪。 |
join | 调用某线程的该方法,将当前线与其合并,即等待该线程结束,在执行当前线程 |
Object.wait() | 调用此方法时必须锁定该对象,等待,且放锁,只有用notfiy唤醒 |
![](https://i-blog.csdnimg.cn/blog_migrate/f5de14250129e18f4a32d71744c771ec.jpeg)