1.如何创建一个线程?
* 三种创建线程的方式, * 1.继承Thread类,通过重写run方法创建新的线程,并通过start执行线程 * 2.直线Runnable接口,实现run方法,通过创建线程类的方法用start执行线程 * 3.使用匿名类,继承Thread类,重写run方法
2.常见线程方法
- Thread.sleep();
使进程停顿一定时间 - (Thread) t.join();
等待该进程结束,才会进入到下一个进程 - (Thread) t.setPriority();
设置进程优先级,为1-10,优先级高的先执行 - (Thread) t.yield();
当前线程临时暂停,使其他线程有更多机会占用CPU资源
3.多个线程的同步问题
int a=10000,此时有10000个线程在减1,又有10000个线程在加1,理想结果20000个进程结束之后a还是等于10000,
但实际上并不是,可能大于10000也可能小于10000。
同步问题产生的原因:
假设一个加进程先进入,得到a=10000,正在做增加运算时,一个减进程也进入,获取到的a也是10000,等加进程结束,
a的结果是10001,赋值给a,减进程结束,a的结果是9999,赋值给a,最终a的结果就是9999,本来期望还原值10000,实际得到了9999,在业务上也叫做脏数据
要解决同步问题,用到synchronized关键字
Object someObject =new Object();
synchronized (someObject){
//此处的代码只有占有了someObject后才可以执行
}
synchronized修饰的对象单次只允许一个进程访问,即不会出现a被加进程与减进程同时访问的情况了。
StringBuffer和StringBuilder的区别
StringBuffer的方法都是有synchronized修饰的,StringBuffer就叫做线程安全的类
而StringBuilder就不是线程安全的类
4.常见的线程安全的类
HashMap和HashTable:
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类
StringBuffer 是线程安全的
StringBuilder 是非线程安全的
所以当进行大量字符串拼接操作的时候,如果是单线程就用StringBuilder会更快些,如果是多线程,就需要用StringBuffer 保证数据的安全性,因为StringBuilder不需要同步,更节省时间
ArrayList和Vector
ArrayList类的声明:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Vector类的声明:
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
区别在于Vector是线程安全的类,而ArrayList非线程安全的类
5.死锁
1. 线程1 首先占有对象1,接着试图占有对象2
2. 线程2 首先占有对象2,接着试图占有对象1
3. 线程1 等待线程2释放对象2
4. 与此同时,线程2等待线程1释放对象1
此时,线程1和线程2就会无限等待下去,即出现死锁
6.线程之间的交互
wait(),notify(),notifyAll();
wait()方法暂停当前进程,使其他进程可以访问当前对象,notify()方法通知一个在wait的进程重新继续开始执行后面的工作
7.lock对象
Lock是一个接口,为了使用一个Lock对象,需要用到Lock lock=new ReentrantLock();
lock.lock()方法表示当前线程占用lock对象,其他线程无法访问,与synchronized不同的是,synchronized块结束后,进程会自
动释放对对象的占用,而lock需要通过lock.unlock()手动释放,否则就会出现进程一直占用对象的情况,
lock对象的tryLock方法可以避免死锁,
lock.tryLock(1,TimeUnit.Seconds);意思是给进程1秒钟的时间去占用lock对象,如果未能占用即结束进程,不会出现多个进程互
相竞争资源的死锁。
总结lock与synchronized的区别:::
1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,Lock是代码层面的实现。
2. Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。synchronized不行,会一根筋一直获取下去。 借助Lock的这个特性,就能够规避死锁,synchronized必须通过谨慎和良好的设计,才能减少死锁的发生。
3. synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放, 所以如果忘记了释放锁,一样会造成死锁。
8.原子访问