synchronized和volatile
volatile :保证内存可见性,但是不保证原子性;
synchronized:同步锁,既能保证内存可见性,又能保证原子性;
synchronized实现可重入锁 (1.持有同一锁自动获取 2.继承锁)
锁定的对象有两种:1.类的实例(对象锁) 2.类对象(类锁)
对象锁(synchronized修饰普通方法或代码块) 对象锁已被其他调用者占用,则需要等待此锁被释放
/**
* 对象锁的两种方式
*/
//方式一
private int count =10;
public synchronized void test01() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
//方式二
public void test02() {
synchronized(this) {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
类锁(synchronized修饰静态方法) 所有类实例化对象互斥拥有一把类锁
private static int count =10; /** * 类锁两种表现方式 */ public static synchronized void test01() { count -- ; System.out.println(Thread.currentThread().getName()+"count="+count); } public static void test02() { synchronized(CurrentDemo01.class) { count -- ; System.out.println(Thread.currentThread().getName()+"count="+count); } }
同一字符串常量代表同一把锁对象
//t1执行结束,t2再执行,t1和t2持有同一把锁 public class CurrentDemo03 { String s1 = "yew"; String s2 = "yew"; public void test01(){ synchronized (s1){ System.out.println(Thread.currentThread().getName()+"---start"); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { System.out.println("interrupt"); } System.out.println(Thread.currentThread().getName()+"---end"); } } public void test02(){ synchronized (s2){ System.out.println(Thread.currentThread().getName()+"---start"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("interrupt"); } System.out.println(Thread.currentThread().getName()+"---end"); } } public static void main(String[] args) { CurrentDemo03 demo3 = new CurrentDemo03(); new Thread(demo3::test01,"t1").start(); new Thread(demo3::test02,"t2").start(); } }
synchronized同步代码块粒度越小,执行效率越高
public class CurrentDemo04 { //总数 private static int count = 0; public synchronized void test01() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"---start"); TimeUnit.SECONDS.sleep(2); for (int i = 0; i <10000000 ; i++) { count++ ; } TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+"---end"); } public void test02() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"---start"); TimeUnit.SECONDS.sleep(2); synchronized (this){ for (int i = 0; i <10000000 ; i++) { count++ ; } } TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+"---end"); } //demo04.test01();8043ms // demo04.test02();4116ms public static void main(String[] args){ CurrentDemo04 demo04 = new CurrentDemo04(); long start = System.currentTimeMillis(); new Thread(new Runnable() { @Override public void run() { try { demo04.test02(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { demo04.test02(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); System.out.println(Thread.activeCount()); while(Thread.activeCount()>2){ Thread.yield(); } long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)+"ms"); System.out.println(count); } }
synchronized方法正常返回或者抛异常而终止,jvm会自动释放对象锁(捕获异常则不会自动释放)
public class CurrentDemo08 { //总数值 private int count = 0; public synchronized void test01() throws Exception { System.out.println(Thread.currentThread().getName()+"---start"); while (true){ count++ ; TimeUnit.SECONDS.sleep(1); if(count <5){ System.out.println(count); }else{ try { int m = count/0; }catch (Exception e){ System.out.println("ERROR :"+e.getMessage()); // return; } } } } public synchronized void test02() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"----start"); TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+"---end"); } public static void main(String[] args) { CurrentDemo08 demo08 = new CurrentDemo08(); new Thread(()-> { try { demo08.test01(); } catch (Exception e) { System.out.println("test01中断"); } },"t1").start(); new Thread(()-> { try { demo08.test02(); } catch (InterruptedException e) { System.out.println("test02中断"); } },"t2").start(); } }
/** * @author yew * @date on 2019/11/18 - 11:49 * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数, * 当个数到5个时,线程2给出提示并结束线程2 * 1.无volatile,线程间不可见,线程t2不会结束 * 2.volatile可以保证原子的可见性,存在不确定性 while(true) 占用CPU资源 */ public class CurrentDemo11 { //List<Object> lists = new ArrayList<Object>(); volatile List<Object> lists = new ArrayList<Object>(); public void add(Object s) { lists.add(s); } public int size() { return lists.size(); } public static void main(String[] args) { CurrentDemo11 demo11 = new CurrentDemo11(); new Thread(() -> { for (int i = 0; i < 10; i++) { demo11.add(new Object()); System.out.println("add Object" + (i + 1)); try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t1线程结束"); }, "t1").start(); new Thread(() -> { System.out.println("t2线程开始"); while (true) { if (demo11.size() == 5){ break; } } System.out.println("t2线程结束"); }, "t2").start(); } } 优化上述问题:
/** * @author yew * 1.wait----notify(随机唤醒持有当前锁且等待的某个线程)/notifyAll(唤醒持有当前锁所有的等待线程) * notify随机唤醒持有锁等待的线程,但是不会释放当前持有的锁 所以监控线程不会立马结束 * 2.countdownLatch */public class CurrentDemo12 { List lists = new ArrayList(); public int size() { return this.lists.size(); } public void add(Object obj) { this.lists.add(obj); } public static void main(String[] args) { CurrentDemo12 demo12 = new CurrentDemo12(); Object lock = new Object(); //先启用t2进行监听 new Thread(()->{ synchronized (lock){ System.out.println("t2线程启动"); if(demo12.size() != 5){ try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2线程结束"); lock.notify(); } },"t2").start(); new Thread(()->{ synchronized (lock){ System.out.println("t1线程启动"); for (int i = 0; i < 10 ; i++) { System.out.println("add Object"+(i+1)); demo12.add(new Object()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } if(demo12.size() == 5){ lock.notify(); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("t1线程结束"); } }).start(); }}
/** * 面试题:写一个固定容量同步容器,拥有Put和get方法,以及getCount方法, * 能够支持两个生产者线程以及10个消费者线程的阻塞调用 * wait notifyAll */ public class CurrentDemo13 { private static final int MAX = 20; private final LinkedList<Object> list = new LinkedList<>(); static int count; public synchronized void put(Object obj){ while (list.size() == MAX){ try { this.wait(); } catch (InterruptedException e) { System.out.println(); } } list.add(obj); ++count; System.out.println("生产后剩余数量"+count); this.notifyAll(); } public synchronized Object get(){ while (list.size()==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } Object t = list.removeFirst(); --count; System.out.println("消费后剩余数量"+count); this.notifyAll(); return t; } public int getCount(){ return count; } public static void main(String[] args) { CurrentDemo13 demo13 = new CurrentDemo13(); //创建生产者 for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { while (true){ demo13.put(Thread.currentThread().getName()+"---"+count); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { while (true){ System.out.println(demo13.get()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } }
/** * condition:在某种状态下 */public class CurrentDemo14 { LinkedList<Object> lists = new LinkedList<>(); private static final int MAX = 20; private static int count = 0; ReentrantLock lock = new ReentrantLock(); Condition producer = lock.newCondition(); Condition consumer = lock.newCondition(); public void put(Object obj){ try { lock.lock(); while (lists.size()==MAX){ producer.await(); } lists.add(obj+"----"+count); count++; System.out.println("生产后剩余:"+count); Thread.sleep(500); consumer.signalAll(); } catch (Exception e) { System.out.println("生产线程异常中断"+e.getMessage()); }finally { lock.unlock(); } } public Object get(){ Object t = null; try { lock.lock(); while (lists.size()==0){ consumer.await(); } t = lists.removeFirst(); System.out.println("已消费对象:"+t); count--; System.out.println("消费后剩余:"+count); Thread.sleep(2000); producer.signalAll(); } catch (Exception e) { System.out.println("消费线程异常中断"+e.getMessage()); }finally { lock.unlock(); return t; } } public static void main(String[] args){ CurrentDemo14 currentDemo14 = new CurrentDemo14(); for (int i = 0; i < 2; i++) { new Thread("p"+i){ public void run(){ for (;;) { currentDemo14.put(Thread.currentThread().getName()); } } }.start(); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { new Thread("c"+i){ public void run(){ for (;;) { currentDemo14.get(); } } }.start(); } }}
/** * ReentrantLock * ReentrantLock同synchronized效果相同 * 1.synchronized遇到异常,自动释放锁,reentranLock需要手动释放锁,所以释放锁需要放在finally代码块执行; * 2.tryLock() 尝试拿锁,拿不到锁的时候可以根据返回的boolean值来决定是否继续执行 * 3.lockInterruptibly()可以对线程中断做出反应 */ public class CurrentDemo15 { ReentrantLock lock = new ReentrantLock(); public void test01(){ try{ lock.lock(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+"test 01"); int t = 10/0; }catch (Exception e){ System.out.println("ERROR"); }finally { lock.unlock(); } } public void test02(){ try{ // lock.tryLock(3, TimeUnit.SECONDS); // lock.lockInterruptibly(); lock.lock(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+"test 02"); }catch (Exception e){ System.out.println("ERROR"); }finally { lock.unlock(); } } public static void main(String[] args) { CurrentDemo15 currentDemo15 = new CurrentDemo15(); new Thread("t1"){ public void run(){ currentDemo15.test01(); } }.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Thread t2 = new Thread("t2"){ public void run(){ currentDemo15.test02(); } }; t2.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); } }
原文地址:https://www.cnblogs.com/vincentYw/p/11834793.html
时间: 2024-11-09 02:48:12