一、synchronized锁范围
synchronized实现同步的基础:
- 对于普通同步方法,锁的是当前实例对象
- 对于静态同步方法,锁的是当前Class
- 对于同步方法块,锁的是synchronized括号范围内的对象
Java中的每个对象都可以作为锁
- 公平锁与非公平锁
// 默认空参构造就是非公平锁,传入一个false也可以
ReentrantLock reentrantLock = new ReentrantLock(false);
// 参数为true表示公平锁
ReentrantLock reentrantLock = new ReentrantLock(true);
- 死锁
//先准备两个对象
static Object a = new Object();
static Object b = new Object();
new Thread(() -> {
synchronized (a) {
System.out.println("a持有锁,等待获取所有b");
synchronized (b) {
System.out.println("b持有锁,等待获取锁a");
}
}
}, "线程名称:a").start();
new Thread(() -> {
synchronized (b) {
System.out.println("b持有锁,等待获取所有a");
synchronized (a) {
System.out.println("a持有锁,等待获取锁b");
}
}
}, "线程名称:b").start();
如何查看程序是否有死锁:
在命令行输入:jps -l
就会显示进程id
然后再输入命令:jstack 58888(进程Id)
就可以看到有一个死锁进程
二、Callable接口
创建线程的方式:
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 线程池中的线程工厂
为了获得线程执行完获得返回结果:
- Runnable和Callable的比较:
- Callable可以获得返回结果
- Callable如果获取不到结果,则会抛除异常
和Runnable和Callable都存在关联的实现类FutureTask:
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> vFutureTask = new FutureTask<>(() -> 200);
Thread thread = new Thread(vFutureTask, "futureTask");
thread.start();
while (!vFutureTask.isDone()){
System.out.println("未计算完成,等待...");
}
System.out.println(vFutureTask.get());
}