Java多线程与锁(同步处理)
Synchronized用法
- 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码, 作用的对象是调用这个代码块的对象;
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法, 作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法, 作用的对象是这个类的所有对象;
- 修饰一个类,其作用的范围是synchronized后面括号括起来的部分, 作用的对象是这个类的所有对象。例如:synchronized(ClassName.class)
Lock的优点
(1)synchronized关键字来实现同步,会导致一个操作必须等前面占用的线程完成其他线程才能进行,而lock可以解决这个问题
(2)线程因为耗时过长(io或者sleep阻塞),我们需要一种机制能停止线程或响应中断。
(3)Lock可以知道线程有没有成功获取到锁,这个也是synchronized无法办到的。
释放锁的方法
synchronize满足下列三个条件之一释放锁
占有锁的线程执行完毕
占有锁的线程异常退出
占有锁的线程进入waiting状态释放锁
Lock必须调用unlock()方法
Lock接口的唯一实现ReentrantLock
注意点:
Lock不是Java语言内置的,synchronized是Java语言的关键字
synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
使用范例
synchronized
修饰方法示例
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public synchronized String getName() throws InterruptedException {
System.out.println("start");
Thread.sleep(1000);
System.out.println("end");
return name;
}
}
public class ThreadThread extends Thread{
private Item item;
public ThreadThread(Item item) {
this.item = item;
}
@Override
public void run() {
super.run();
while(true){
try {
System.out.println(Thread.currentThread().getName() + "-----" + item.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Item item = new Item("123");
ThreadThread thread1 = new ThreadThread(item);
ThreadThread thread2 = new ThreadThread(item);
thread1.start();
thread2.start();
}
运行结果能看出同一时间只有一个线程可以执行synchronize修饰的方法。
lock
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
一般使用模版
Lock lock = new 具体实现该接口;
lock.lock();
try{
//处理任务
}catch(Exception ex){
}finally{
//释放锁
lock.unlock();
}
或者这样
Lock lock = new 具体实现该接口;
if(lock.tryLock()) {
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock();
}
}else {
//如果不能获取锁,则直接做其他事情
}
ReentrantLock实现了Lock的类
利用上面的例子稍加修改,运行结果与synchronize实现一致
public class Item {
private String name;
private Lock lock = new ReentrantLock();
public Item(String name) {
this.name = name;
}
public String getName() throws InterruptedException {
try {
lock.lock();
System.out.println("start");
Thread.sleep(1000);
System.out.println("end");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return name;
}
}