特点: 1 线程可见性 2 禁止指令重排序 3但是不保证原子性操作
原子性 ,可见性,可重入锁,异常会释放锁,非公平锁
1 加在方法上,如果是非静态方法就是锁住了这个对象,这个对象多个Synchronized方法只能执行一个
2 加在方法上,如果是静态方法就是锁住了这个类,这个类多个Synchronized方法只能执行一个
3 加在对象上,Synchronized 对象同样的代码段只能执行一个
4 加在class上,Synchronized 同样的类代码段只能执行一个
偏向锁-》自旋锁-》重量锁
偏向锁:一个线程的时候记录这个线程,下次默认锁就是他的
自旋锁:多于一个线程,就会转换成自旋锁,默认自旋10次进入队列
重量锁:进入cpu队列不耗费cpu资源
自旋锁 什么时候用?执行时间短,线程少
系统锁 什么时候用?执行时间长,线程多
Synchronized 锁优化:
1 锁细化锁的代码越少越好
2 锁粗化,合并多个小锁
不能当为锁的对象:
String,Integer,Character、Short、Long因为有缓存,会导致对象改变问题(基础类型int啥的也不行)
死锁的例子:
https://www.cnblogs.com/pweizhao/articles/9066728.html
AtomicInteger 线程安全的integer 好多Atomic开口的类都是线程安全的
用 increamnet添加数
这些类保证线程安全用的是Cas(要改的值V,期望值Expected,改后的值NewValue) CPU指令级别中间不会被打断
Unsafe 类 直接操作java虚拟机内存
基于CAS实现的类java.util.concurrent.atomic
1 如果有3个线程 分别是 +1 -1 +1的操作 从结果来说是没区别的
2 但是对象类型的就不行,是有区别的,要加版本号解决这个问题
例子
static long count2 = 0L; static AtomicLong count1 = new AtomicLong(0L); static LongAdder count3 = new LongAdder(); public static void main(String[] args) throws Exception { Thread[] threads = new Thread[1000]; for(int i=0; i<threads.length; i++) { threads[i] = new Thread(()-> { for(int k=0; k<100000; k++) count1.incrementAndGet(); }); } long start = System.currentTimeMillis(); for(Thread t : threads ) t.start(); for (Thread t : threads) t.join(); long end = System.currentTimeMillis(); //TimeUnit.SECONDS.sleep(10); System.out.println("Atomic: " + count1.get() + " time " + (end-start)); //----------------------------------------------------------- Object lock = new Object(); for(int i=0; i<threads.length; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int k = 0; k < 100000; k++) synchronized (lock) { count2++; } } }); } start = System.currentTimeMillis(); for(Thread t : threads ) t.start(); for (Thread t : threads) t.join(); end = System.currentTimeMillis(); System.out.println("Sync: " + count2 + " time " + (end-start)); //---------------------------------- for(int i=0; i<threads.length; i++) { threads[i] = new Thread(()-> { for(int k=0; k<100000; k++) count3.increment(); }); } start = System.currentTimeMillis(); for(Thread t : threads ) t.start(); for (Thread t : threads) t.join(); end = System.currentTimeMillis(); //TimeUnit.SECONDS.sleep(10); System.out.println("LongAdder: " + count1.longValue() + " time " + (end-start)); }输出
Atomic: 100000000 time 1523 Sync: 100000000 time 3819 LongAdder: 100000000 time 454
结论
Atomic 用的cas所以快于Sync
LongAdder 用的分段锁+cas ,线程越多比Atomic越快,线程少Atomic快
1 ReentrantLock
使用 Lock lock= new ReentrantLock 加锁Lock.lock 解锁Lock.unlock
比snchronized的好处
1 trylock 可以申请几秒之内得到一把锁
2 lockinterruptibly
3 公平锁排队取锁
例子:
//private static ReentrantLock lock=new ReentrantLock(true); //参数为true表示为公平锁,请对比输出结果 public static void main(String[] args) { Lock lock = new ReentrantLock(); Thread t1 = new Thread(()->{ try { lock.lock(); System.out.println("t1 start"); TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); System.out.println("t1 end"); } catch (InterruptedException e) { System.out.println("interrupted!"); } finally { lock.unlock(); } }); t1.start(); Thread t2 = new Thread(()->{ try { //lock.lock(); lock.lockInterruptibly(); //可以对interrupt()方法做出响应 System.out.println("t2 start"); TimeUnit.SECONDS.sleep(5); System.out.println("t2 end"); } catch (InterruptedException e) { System.out.println("interrupted!"); } finally { lock.unlock(); } }); t2.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); //打断线程2的等待 }2 ReadWriteLock
读锁 可以有多个读锁与写锁互斥
写锁 只能有一个写锁
例子:
static Lock lock = new ReentrantLock(); private static int value; static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); static Lock readLock = readWriteLock.readLock(); static Lock writeLock = readWriteLock.writeLock(); public static void read(Lock lock) { try { lock.lock(); Thread.sleep(1000); System.out.println("read over!"); //模拟读取操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void write(Lock lock, int v) { try { lock.lock(); Thread.sleep(1000); value = v; System.out.println("write over!"); //模拟写操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) { //Runnable readR = ()-> read(lock); Runnable readR = ()-> read(readLock); //Runnable writeR = ()->write(lock, new Random().nextInt()); Runnable writeR = ()->write(writeLock, new Random().nextInt()); for(int i=0; i<18; i++) new Thread(readR).start(); for(int i=0; i<2; i++) new Thread(writeR).start(); }