目录
线程的生命周期
阻塞的三种情况:
等待阻塞:运行的线程执行wait方法,需要notify()、notifyAll()方法唤醒
同步阻塞:synchronized 运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。
其他阻塞:运行的线程执行sleep或join方法,或者发出了I/O请求时
线程安全三种解决方法
java中通过同步机制解决线程安全问题:
方式一、同步代码块
synchronized(同步监视器){
//需要被同步的代码部分
}
说明:操作的是多个线程共同操作的变量
同步监视器为任意一个类的对象,都可以充当锁
注意:多个线程必须共用一把锁。如果是实现Runnable接口,视情况可以用this代表锁 或者类的class(类只会被加载一次)
方式二、同步方法
说明:同步方法仍涉及到同步监视器,只是不显式声明
静态的同步方法,同步监视器是this
非静态的同步方法,同步监视器是当前类本身
public synchronized int method1(){
//需要被同步的部分
}
方式三、lock锁
ReentrantLock实现接口Lock()
//解决线程同步安全方式三 jdk1.5以后新增lock锁
class Task2 implements Runnable {
private int ticket = 100;
//实例化lock
private ReentrantLock r = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
//调用锁定方法lock()
r.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "剩余票数" + ticket);
ticket--;
}
else {
break;
}
}finally {
//调用解锁方法
r.unlock();
}
}
}
}
线程死锁
死锁:就是不同的线程抢占了对方需要的同步资源不释放,都在等待对方释放,就形成了死锁
说明:出现死锁不会出现异常及提示,所有线程处于阻塞状态。
死锁实例:
StringBuffer s1=new StringBuffer();
StringBuffer s2=new StringBuffer();
new Thread(){
@Override
public void run() {
synchronized(s1){
s1.append("a");
s2.append("1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2){
s1.append("b");
s2.append("2");
System.out.println(s1);
System.out.println(s2);
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(s2){
s1.append("c");
s2.append("3");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1){
s1.append("d");
s2.append("4");
System.out.println(s1);
System.out.println(s2);
}
}
}
}).start();