网站运营 网站建设疫情防控最新信息
Synchronized
称之为”同步锁
作用:
保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果
用法:
1.修饰方法:方法锁,锁的对象是当前对象
2.修饰静态方法:类锁,锁的对象是当前的类,实际是这个类的.class对象
3.修饰代码块:对象锁,锁的对象是synchronized修饰的对象
案例:
public class TestThread {public static void main(String[] arge){Ticket ticket = new Ticket();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"A").start();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"B").start();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"C").start();}
}class Ticket{private int num = 20;synchronized void ticket(){if(num > 0){System.out.println(Thread.currentThread().getName()+"剩余票数:"+num--);}}
}
修饰方法:
public synchronized void method()
{
}
修饰代码块:
class SyncThread implements Runnable {private static int count;public SyncThread() {count = 0;}public void run() {synchronized(this) {for (int i = 0; i < 5; i++) {try {System.out.println(Thread.currentThread().getName() + ":" + (count++));Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}public int getCount() {return count;}
}public class Demo00 {public static void main(String args[]){ SyncThread s = new SyncThread();Thread t1 = new Thread(s);Thread t2 = new Thread(s);t1.start();t2.start();}
}
修饰类:
给class加锁和上例的给静态方法加锁是一样的,所有对象公用一把锁
class ClassName {public void method() {synchronized(ClassName.class) {}}
}
注意:
1.在定义接口方法时不能使用synchronized关键字;构造方法不能使用synchronized关键字
2.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制
3.每个对象只有一个锁与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码
Lock
Lock是一个同步线程机制;
主要方法:
lock():获取锁,加锁
tryLock():判断锁是否可用
unlock():释放锁
使用:
public class TestThread2 {public static void main(String[] arge){Ticket2 ticket = new Ticket2();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"A").start();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"B").start();new Thread(()->{for(int i=1;i<40;i++){ticket.ticket();}},"C").start();}
}class Ticket2{private int num = 20;void ticket(){Lock lock = new ReentrantLock();lock.lock();try{if(num > 0){System.out.println(Thread.currentThread().getName()+"剩余票数:"+num--);}}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}
}
ReentrantLock
重入锁也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。避免死锁问题
public class ReentrantDemo implements Runnable {Lock lock = new ReentrantLock();@Overridepublic void run() {set();}public void set() {try {lock.lock();System.out.println("set 方法");get();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();// 必须在finally中释放}}public void get() {try {lock.lock();System.out.println("get 方法");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String[] args) {ReentrantDemo reentrantDemo = new ReentrantDemo();new Thread(reentrantDemo).start();}
}
同一个线程,首先在set方法中获取锁,然后调用get方法,get方法中重复获取同一个锁。两个方法都执行成功
ReentrantReadWriteLock
读写锁,可以分别获取读锁或写锁。
特点:
读锁使用共享模式;写锁使用独占模式;读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁
常用方法:
writeLock():获取写锁
readLock():获取读锁
区别:
1.synchronized内置关键字;lock是一个Java类
2.synchronized无法判断锁状态;lock可以判断是否获取到锁
3.synchronized会自动释放锁;lock必须手动释放锁,不释放会造成死锁
4.synchronized可重入锁,不可以中断,非公平;lock可重入锁,可以判断锁,非公平(可以设置)
5.synchronized适合锁少量的代码同步问题;lock适合锁大量的同步代码