synchronized和Lock的区别
synchronized和Lock的区别:
1、Lock是个接口,而synchronized是java关键字,synchronized是内置语言实现
2、synchronized是jdk1.0版本提供的,Lock是jdk1.5提供的
3、synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象的发生;而Lock在发生异常时,如果没有主动通过unlock()去释放锁,则很有可能造成死锁现象,因此使用Lock时需要在finally块中释放锁
4、Lock可以让等待锁的线程相应中断;而synchronized不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
synchronized关键字的使用:
//synchronized语法块
synchronized(对象){
需要加锁的代码
}
// synchronized可以修饰方法
强调:建议锁的范围越小越好
以下为synchronized的两个使用案例:synchronized语法块
public class TestThread03 {
public static void main(String[] args) {
MyThread04 mt = new MyThread04();
Thread m1 = new Thread(mt);
Thread m2 = new Thread(mt);
m1.start();
m2.start();
}
}
class MyThread04 extends Thread{
private int id;
private Object key = new Object();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (key) {
id++;
}
}
System.out.println(Thread.currentThread().getName() + "--结果是:"+ id);
}
}
synchronized修饰方法
public class TestThread03 {
public static void main(String[] args) {
MyThread04 mt = new MyThread04();
Thread m1 = new Thread(mt);
Thread m2 = new Thread(mt);
m1.start();
m2.start();
}
}
class MyThread04 extends Thread{
private int id;
private Object key = new Object();
@Override
public synchronized void run() {
for (int i = 0; i < 1000000; i++) {
id++;
}
System.out.println(Thread.currentThread().getName() + "--结果是:"+ id);
}
}
Lock由jdk1.5提供的
lock接口的实现必须实现他的子类ReentrantLock()方法
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestThread04 {
public static void main(String[] args) {
MyThread05 mt = new MyThread05();
Thread m1 = new Thread(mt);
Thread m2 = new Thread(mt);
m1.start();
m2.start();
}
}
class MyThread05 extends Thread{
private int id;
private Object key = new Object();
// 冲入锁 jdk1.5提供的
Lock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
try {
// 加锁
lock.lock();
id++;
} finally {
// 释放锁
lock.unlock();
}
}
System.out.println(Thread.currentThread().getName() + "--结果是:"+ id);
}
}
线程生命周期及转换问题
概述:
当线程被创建以后,它不是一启动(start)就进入运行状态的,也不是一直处于执行状态。在线程的生命周期中,它要经过new(创建线程) 、ready(就绪) 、running(运行)、 block(阻塞) 、destroy(销毁)这五种状态。当线程进入运行状态后,它不是一直“霸占”CPU运行,一般的操作系统是采用抢占式的方式来让线程获得CPU。所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞、就绪之间切换。
线程的创建:
当程序使用new关键字创建一个线程以后,该线程就处于新建状态,此时它和其他的JAVA对象一样,仅仅由JAVA虚拟机为其分配内存,并初始化成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。
运行和阻塞状态:
当处于就绪状态的线程获得CPU,它就会执行run()方法(所以run()方法是由线程获得CPU以后自动执行),线程就进入了运行状态。如果一个计算机只有一个CPU,那么在任意时刻只有一个线程处于运行状态。相对的,如果有多个CPU,那么在同一时刻就可以有多个线程并行执行。
当正在执行的线程被阻塞以后,其他线程可以获得执行的机会,被阻塞的线程会在合适的时候进入就绪状态,而不是进入运行状态。
线程间的转换图:
线程死亡:
1、run()/call()方法执行完成,线程正常结束;
2、直接调用线程的stop()方法结束该线程——该方法容易导致死锁,通常不建议使用。
注意:一旦当子线程启动以后,它就拥有和主线程一样的地位,它不会受主线程的影响。线程提供了一个isAlive()方法,当调用线程对象的isAlive()方法,如果该线程处于就绪、运行、阻塞三种状态时,该方法返回true;当线程处于新建、死亡两种状态时,返回false。