线程的生命周期
- 新建:创建线程对象(new 的过程);
- 就绪:有执行资格,但是没有执行权(start());
- 运行:有执行资格,有执行权;
* 阻塞:由于一些操作让线程处于改状态,没有执行资格也没有自行权;
而另外一些操作可以将它激活,激活后处于就绪状态。 - 死亡:线程对象变成垃圾,等待被回收。
线程同步
1.保护线程安全的一种手段;
2.保证了多线程情况下共享数据不会混乱;
3.同一时间点内,只有一个线程能够进来执行共享数据;
同步的方法 sysnchronized
- 同步方法;
普通方法中的锁对象默认是this,这个类的对象,在重写run方法时,不能锁定this关键字,因为this代表的是本类对象,而不是代码块; - 同步代码块;
静态方法中的锁对象默认是 当前类名.class; - 同步方法在Thread的子类里面使用,必须加static修饰,锁对象是当前类的对象;
- Lock锁机制:
Lock锁的使用必须结合try{加锁}finally{释放锁},锁对象是当前类对象。
public class TestThread3 implements Runnable {
int ticketNum = 10;
static Lock lock = new ReentrantLock();//加Lock锁
@Override
public void run() {
while (true) {
lock.lock();//如果只是简单的在这里加锁,在输出完解锁,那么程序就会处于死锁状态
if (ticketNum <= 0) {
System.out.println("没有票了");//这里没有票了,然后程序直接break,没有解锁,所以,会处于死锁状态
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了第" + ticketNum-- + "张票");
lock.unlock();//解锁
}
}
public static void main(String[] args) {
TestThread3 thread = new TestThread3();
new Thread(thread,"黄牛").start();
new Thread(thread,"小明").start();
new Thread(thread,"老师").start();
}
}
程序的运行结果
但是如果在加锁,解锁的时候加上try {}finally{},就不会,因为finally后面的代码块,总会被执行。
public void run() {
while (true) {
try {
lock.lock();
if (ticketNum <= 0) {
System.out.println("没有票了");
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了第" + ticketNum-- + "张票");
} finally {
lock.unlock();
}
}
}
下面截图是程序运行结果,不会造成死锁。
volatile与sysnchronized区别
- 关键字 volatile:能够使变量在值发生改变时,能尽快的让其他线程知道。本质是告诉jvm当前变量在寄存器中的值是不确定的,需要从主存读取;
- 关键字 sysnchronized:锁定当前变量,只有当前线程可以访问改变了,其他线程被阻塞;