第44天学习打卡(JUC 线程和进程 并发和并行 Lock锁 生产者和消费者问题 如何判断锁(8锁问题) 集合类不安全)教程
什么是JUC
1.java.util工具包 包 分类
业务:普通的线程代码 Thread
Runnable 没有返回值、效率相比Callable相对较低
2.线程和进程
进程:一个程序。QQ.exe,Music.exe 程序的集合
一个进程往往可以包含多个线程,至少包含一个!
Java默认有几个线程:2个 main、GC
线程:开了一个进程Typora,写字(一个线程在输入),自动保存(线程负责的)
对于Java而言开启线程的方式:Thread、Runnable、Callable
Java真的可以开启线程吗? 开不了
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> public synchronized void start() {<br></br> /**<br></br> * This method is not invoked for the main method thread or "system"<br></br> * group threads created/set up by the VM. Any new functionality added<br></br> * to this method in the future may have to also be added to the VM.<br></br> *<br></br> * A zero status value corresponds to state "NEW".<br></br> */<br></br> if (threadStatus != 0)<br></br> throw new IllegalThreadStateException();<br></br> <br></br> /* Notify the group that this thread is about to be started<br></br> * so that it can be added to the group's list of threads<br></br> * and the group's unstarted count can be decremented. */<br></br> group.add(this);<br></br> <br></br> boolean started = false;<br></br> try {<br></br> start0();<br></br> started = true;<br></br> } finally {<br></br> try {<br></br> if (!started) {<br></br> group.threadStartFailed(this);<br></br> }<br></br> } catch (Throwable ignore) {<br></br> /* do nothing. If start0 threw a Throwable then<br></br> it will be passed up the call stack */<br></br> }<br></br> }<br></br> }<br></br> //本地方法 调用底层的C++,java是运行在虚拟机上的,无法操作硬件<br></br> private native void start0();<br></br>
并发 、并行
并发编程:并发 并行
并发(多线程操作桶一个资源)
并行(多个人一起行走)
并发:若CPU只有一核(一瞬间只能处理一个东西),想要模拟出来多条线程,则需要快速交替。
并行:若CPU多核,多个线程可以同时执行,用线程池提高性能
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.demo06;<br></br> <br></br> public class Test1 {<br></br> public static void main(String[] args) {<br></br> <br></br> //获取CPU的核数<br></br> System.out.println(Runtime.getRuntime().availableProcessors());<br></br> <br></br> <br></br> }<br></br> }<br></br>
并发编程的本质:充分利用CPU的资源
线程有几个状态
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> public enum State {<br></br> /**<br></br> * Thread state for a thread which has not yet started.<br></br> */<br></br> //线程新生<br></br> NEW,<br></br> <br></br> /**<br></br> * Thread state for a runnable thread. A thread in the runnable<br></br> * state is executing in the Java virtual machine but it may<br></br> * be waiting for other resources from the operating system<br></br> * such as processor.<br></br> */<br></br> //运行状态<br></br> RUNNABLE,<br></br> <br></br> /**<br></br> * Thread state for a thread blocked waiting for a monitor lock.<br></br> * A thread in the blocked state is waiting for a monitor lock<br></br> * to enter a synchronized block/method or<br></br> * reenter a synchronized block/method after calling<br></br> * {@link Object#wait() Object.wait}.<br></br> */<br></br> //阻塞<br></br> BLOCKED,<br></br> <br></br> /**<br></br> * Thread state for a waiting thread.<br></br> * A thread is in the waiting state due to calling one of the<br></br> * following methods:<br></br> * <ul><br></br> * <li>{@link Object#wait() Object.wait} with no timeout</li><br></br> * <li>{@link #join() Thread.join} with no timeout</li><br></br> * <li>{@link LockSupport#park() LockSupport.park}</li><br></br> * </ul><br></br> *<br></br> * <p>A thread in the waiting state is waiting for another thread to<br></br> * perform a particular action.<br></br> *<br></br> * For example, a thread that has called <tt>Object.wait()</tt><br></br> * on an object is waiting for another thread to call<br></br> * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on<br></br> * that object. A thread that has called <tt>Thread.join()</tt><br></br> * is waiting for a specified thread to terminate.<br></br> */<br></br> //等待 <br></br> WAITING,<br></br> <br></br> /**<br></br> * Thread state for a waiting thread with a specified waiting time.<br></br> * A thread is in the timed waiting state due to calling one of<br></br> * the following methods with a specified positive waiting time:<br></br> * <ul><br></br> * <li>{@link #sleep Thread.sleep}</li><br></br> * <li>{@link Object#wait(long) Object.wait} with timeout</li><br></br> * <li>{@link #join(long) Thread.join} with timeout</li><br></br> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li><br></br> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li><br></br> * </ul><br></br> */<br></br> //超时等待 死死的等<br></br> TIMED_WAITING,<br></br> <br></br> /**<br></br> * Thread state for a terminated thread.<br></br> * The thread has completed execution.<br></br> */<br></br> //终止<br></br> TERMINATED;<br></br> }<br></br>
wait/sleep区别
1.来自不同的类
wait=>Object
sleep=>Thread
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> TimeUnit.DAYS.sleep(1);<br></br> TimeUnit.SECONDS.sleep(2);
2关于锁的释放
wait会释放锁
sleep不会释放锁 抱着锁睡觉不会放锁
3使用范围不同
wait:必须在同步代码块中
sleep:可以在任何地方
4 是否需要捕获异常
wait不需要捕获异常
sleep必须要捕获异常
3、Lock锁(重点)
传统synchronized
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.demo06;<br></br> //基本的卖票例子<br></br> /**<br></br> * 真正的多线程开发,公司中的开发,降低耦合性<br></br> *线程就是一个单独的资源类,没有任何附属的操作<br></br> * 1.属性、方法<br></br> */<br></br> <br></br> public class SaleTicketDemo01 {<br></br> public static void main(String[] args) {<br></br> //并发:多线程操作同一个资源类,把资源丢入线程<br></br> Ticket ticket = new Ticket();<br></br> //@FunctionalInterface 函数式接口,jdk1.8后 lambda表达式(参数)->{代码}<br></br> new Thread(()->{<br></br> for (int i = 0; i < 40; i++) {<br></br> ticket.sale();<br></br> }<br></br> <br></br> },"A").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 40; i++) {<br></br> ticket.sale();<br></br> }<br></br> },"B").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 40; i++) {<br></br> ticket.sale();<br></br> }<br></br> },"C").start();<br></br> <br></br> }<br></br> }<br></br> <br></br> //资源类OOP<br></br> class Ticket{<br></br> //属性,方法<br></br> private int number = 30;<br></br> <br></br> //卖票的方式<br></br> //synchronized 本质:队列 锁<br></br> public synchronized void sale(){<br></br> if (number>0){<br></br> System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余"+number);<br></br> }<br></br> }<br></br> //锁 锁的是对象<br></br> //锁class<br></br> <br></br> }
公平锁:十分公平:可以先来后到(即排队)
非公平锁:十分公平:可以插队(默认)
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.demo06;<br></br> <br></br> import java.util.concurrent.locks.Lock;<br></br> import java.util.concurrent.locks.ReentrantLock;<br></br> <br></br> public class SaleTicketDemo02 {<br></br> public static void main(String[] args) {<br></br> //并发:多线程操作同一个资源类,把资源丢入线程<br></br> Ticket2 ticket = new Ticket2();<br></br> //@FunctionalInterface 函数式接口,jdk1.8后 lambda表达式(参数)->{代码}<br></br> new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"A").start();<br></br> new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"B").start();<br></br> new Thread(()->{ for (int i = 0; i < 40; i++) ticket.sale(); },"C").start();<br></br> <br></br> }<br></br> }<br></br> <br></br> //Lock三部曲<br></br> // 1.new ReentrantLock();<br></br> //2.Lock.lock();//加锁<br></br> //3.finally=> lock.unlock();//解锁<br></br> <br></br> class Ticket2{<br></br> //属性,方法<br></br> private int number = 30;<br></br> Lock lock = new ReentrantLock();<br></br> <br></br> //卖票的方式<br></br> <br></br> public void sale(){<br></br> lock.lock();//加锁<br></br> try{<br></br> //业务代码<br></br> if (number>0){<br></br> System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余"+number);<br></br> }<br></br> <br></br> <br></br> }catch (Exception e){<br></br> e.printStackTrace();<br></br> }finally{<br></br> lock.unlock();//解锁<br></br> }<br></br> <br></br> }<br></br> <br></br> }<br></br> <br></br> <br></br>
Synchronized和Lock区别
1.Synchronized 是内置的java关键字,Lock是一个java类
2.Synchronized 无法判断获取的状态,Lock可以判断是否获取到了锁
3.Synchronized 会自动释放锁,loack必须要手动释放锁!如果不释放,会造成死锁
4.Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去。
5.Synchronized 可重入锁,不可以中断的,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置);
6.Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码!
4.生产者和消费者问题
面试的时候:单例模式 排序算法 生产者和消费者 死锁
Synchronized 版 wait notify
juc lock
生产者和消费者问题Synchronized 版
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.productorcous;<br></br> /**<br></br> *线程之间的通信问题:生产者和消费者问题!等待唤醒,通知唤醒<br></br> * 线程交替执行 A B 操作同一个变量 num = 0<br></br> * A num + 1<br></br> * B num - 1<br></br> */<br></br> <br></br> public class A {<br></br> public static void main(String[] args) {<br></br> //创建一个资源类<br></br> Data data = new Data();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> try {<br></br> data.increment();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> }<br></br> <br></br> },"A").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.decrement();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"B").start();<br></br> }<br></br> <br></br> <br></br> <br></br> <br></br> }<br></br> <br></br> <br></br> <br></br> //判断等待 业务 通知<br></br> class Data{<br></br> //数字 资源类是独立耦合的<br></br> private int number = 0;<br></br> <br></br> //+1<br></br> //只要是并发编程一定要有锁<br></br> <br></br> public synchronized void increment() throws InterruptedException {<br></br> if (number!=0){//0的时候干活<br></br> //等待操作<br></br> this.wait();<br></br> <br></br> }<br></br> number++;<br></br> System.out.println(Thread.currentThread().getName()+"=>"+number);<br></br> //通知其他线程,我+1完毕了<br></br> this.notifyAll();<br></br> }<br></br> public synchronized void decrement() throws InterruptedException {<br></br> if (number==0){//1的时候干活<br></br> //等待<br></br> this.wait();<br></br> <br></br> }number--;<br></br> System.out.println(Thread.currentThread().getName()+"=>"+number);<br></br> //通知其他线程,我-1完毕了<br></br> this.notifyAll();<br></br> }<br></br> }
问题存在:A B C D4个线程!存在虚假唤醒
if改为while判断
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.productorcous;<br></br> /**<br></br> *线程之间的通信问题:生产者和消费者问题!等待唤醒,通知唤醒<br></br> * 线程交替执行 A B 操作同一个变量 num = 0<br></br> * A num + 1<br></br> * B num - 1<br></br> */<br></br> <br></br> public class A {<br></br> public static void main(String[] args) {<br></br> //创建一个资源类<br></br> Data data = new Data();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> try {<br></br> data.increment();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> }<br></br> <br></br> },"A").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.decrement();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"B").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.increment();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"C").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.decrement();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"D").start();<br></br> }<br></br> <br></br> <br></br> <br></br> <br></br> }<br></br> <br></br> <br></br> <br></br> //判断等待 业务 通知<br></br> class Data{<br></br> //数字 资源类是独立耦合的<br></br> private int number = 0;<br></br> <br></br> //+1<br></br> //只要是并发编程一定要有锁<br></br> <br></br> public synchronized void increment() throws InterruptedException {<br></br> while (number!=0){//0的时候干活<br></br> //等待操作<br></br> this.wait();<br></br> <br></br> }<br></br> number++;<br></br> System.out.println(Thread.currentThread().getName()+"=>"+number);<br></br> //通知其他线程,我+1完毕了<br></br> this.notifyAll();<br></br> }<br></br> public synchronized void decrement() throws InterruptedException {<br></br> while (number==0){//1的时候干活<br></br> //等待<br></br> this.wait();<br></br> <br></br> }number--;<br></br> System.out.println(Thread.currentThread().getName()+"=>"+number);<br></br> //通知其他线程,我-1完毕了<br></br> this.notifyAll();<br></br> }<br></br> }
JUC版的生产者与消费者
通过Lock找到Condition
代码实现:
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.productorcous;<br></br> <br></br> import java.util.concurrent.locks.Condition;<br></br> import java.util.concurrent.locks.Lock;<br></br> import java.util.concurrent.locks.ReentrantLock;<br></br> <br></br> public class B {<br></br> public static void main(String[] args) {<br></br> //创建一个资源类<br></br> Data2 data = new Data2();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> try {<br></br> data.increment();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> }<br></br> <br></br> },"A").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.decrement();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"B").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.increment();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"C").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++)<br></br> try {<br></br> data.decrement();<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> <br></br> },"D").start();<br></br> }<br></br> <br></br> <br></br> }<br></br> <br></br> //判断等待 业务 通知<br></br> class Data2 {<br></br> //数字 资源类是独立耦合的<br></br> private int number = 0;<br></br> Lock lock = new ReentrantLock();<br></br> Condition condition = lock.newCondition();<br></br> // condition.await();//等待<br></br> //condition.signalAll();//唤醒全部<br></br> <br></br> //+1<br></br> //只要是并发编程一定要有锁<br></br> <br></br> public void increment() throws InterruptedException {<br></br> lock.lock();<br></br> try {<br></br> while (number != 0) {<br></br> //0的时候干活<br></br> condition.await();<br></br> }<br></br> number++;<br></br> System.out.println(Thread.currentThread().getName() + "=>" + number);<br></br> //通知其他线程,我-1完毕了<br></br> condition.signalAll();<br></br> } catch (Exception e) {<br></br> e.printStackTrace();<br></br> } finally {<br></br> lock.unlock();<br></br> <br></br> }<br></br> <br></br> }<br></br> <br></br> <br></br> public synchronized void decrement() throws InterruptedException {<br></br> lock.lock();<br></br> try{<br></br> while (number == 0) {//1的时候干活<br></br> //等待<br></br> condition.await();<br></br> <br></br> <br></br> }<br></br> number--;<br></br> System.out.println(Thread.currentThread().getName() + "=>" + number);<br></br> //通知其他线程,我-1完毕了<br></br> condition.signalAll();<br></br> <br></br> }catch (Exception e){<br></br> e.printStackTrace();<br></br> }finally {<br></br> lock.unlock();<br></br> }<br></br> <br></br> }<br></br> }<br></br>
任何一个新的技术,绝对不是仅仅只是覆盖了原来的技术,一定有其优势和补充!
Condition 精准的通知和唤醒线程
代码测试:
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.productorcous;<br></br> <br></br> import java.util.concurrent.locks.Condition;<br></br> import java.util.concurrent.locks.Lock;<br></br> import java.util.concurrent.locks.ReentrantLock;<br></br> <br></br> /**<br></br> *A执行完调用B,B执行完调用C,C执行完调用A<br></br> */<br></br> <br></br> public class C {<br></br> public static void main(String[] args) {<br></br> Data3 data = new Data3();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> data.printA();<br></br> }<br></br> },"A").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> data.printB();<br></br> }<br></br> },"B").start();<br></br> new Thread(()->{<br></br> for (int i = 0; i < 10; i++) {<br></br> data.printC();<br></br> }<br></br> },"C").start();<br></br> }<br></br> }<br></br> class Data3{<br></br> //资源类Lock<br></br> private Lock lock = new ReentrantLock();<br></br> private Condition condition1 = lock.newCondition();<br></br> private Condition condition2 = lock.newCondition();<br></br> private Condition condition3 = lock.newCondition();<br></br> private int number = 1;//为1时 A执行 为2时B执行 为3时 C执行<br></br> public void printA(){<br></br> lock.lock();<br></br> try {<br></br> //业务,判断->执行->通知<br></br> while (number!=1){<br></br> //等待<br></br> condition1.await();<br></br> }<br></br> System.out.println(Thread.currentThread().getName()+"=>AAAAA");<br></br> //唤醒,唤醒指定的人B<br></br> number = 2;<br></br> condition2.signal();<br></br> } catch (Exception e) {<br></br> e.printStackTrace();<br></br> } finally {<br></br> lock.unlock();<br></br> }<br></br> <br></br> <br></br> }<br></br> public void printB(){<br></br> lock.lock();<br></br> try {<br></br> //业务,判断->执行->通知<br></br> while (number!=2){<br></br> condition2.await();<br></br> }<br></br> System.out.println(Thread.currentThread().getName()+"=>BBBBB");<br></br> //唤醒,唤醒指定的人C<br></br> number = 3;<br></br> condition3.signal();<br></br> } catch (Exception e) {<br></br> e.printStackTrace();<br></br> } finally {<br></br> lock.unlock();<br></br> }<br></br> <br></br> <br></br> }<br></br> public void printC(){<br></br> lock.lock();<br></br> try {<br></br> //业务,判断->执行->通知<br></br> while (number!=3){<br></br> condition3.await();<br></br> }<br></br> System.out.println(Thread.currentThread().getName()+"=>CCCCC");<br></br> //唤醒,唤醒指定的人C<br></br> number = 1;<br></br> condition1.signal();<br></br> } catch (Exception e) {<br></br> e.printStackTrace();<br></br> } finally {<br></br> lock.unlock();<br></br> }<br></br> <br></br> <br></br> }<br></br> <br></br> <br></br> <br></br> }
快捷键模式:
ctrl alt+t :try catch的快捷键
或者在菜单栏中点击Code
5 如何判断锁是谁(8锁现象)
*深刻理解锁
对象、Class
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.lock8;<br></br> <br></br> import java.util.concurrent.TimeUnit;<br></br> <br></br> /**<br></br> * 8锁,就是关于锁的8个问题<br></br> *1.标准情况下。两个线程先是发短信 然后是打电话<br></br> * 2.sendSms延迟四秒,两个线程先打印发短信还是先打印打电话 ? 先打印发短信 然后是打电话<br></br> */<br></br> <br></br> public class Test1 {<br></br> public static void main(String[] args) throws InterruptedException {<br></br> Phone phone = new Phone();<br></br> <br></br> //phone.sendSms(); 锁的问题<br></br> <br></br> new Thread(()->{<br></br> phone.sendSms();<br></br> },"A").start();<br></br> <br></br> //捕获<br></br> <br></br> try {<br></br> TimeUnit.SECONDS.sleep(1);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> new Thread(()->{<br></br> phone.call();<br></br> },"B").start();<br></br> <br></br> }<br></br> }<br></br> class Phone{<br></br> //synchronized 锁的对象是方法的调用者 phone是锁<br></br> //两个方法(sendSms call)用的是同一个锁,谁先拿到谁执行<br></br> public synchronized void sendSms(){<br></br> try {<br></br> TimeUnit.SECONDS.sleep(4);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> System.out.println("发短信");<br></br> <br></br> }<br></br> public synchronized void call(){<br></br> System.out.println("打电话");<br></br> <br></br> }<br></br> }<br></br>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.lock8;<br></br> <br></br> import java.util.concurrent.TimeUnit;<br></br> <br></br> /**<br></br> * 3.增加了一个普通方法后 程序是先执行发短息还是hello? 先输出hello 因为它是普通方法没有锁<br></br> * 4.两个对象两个同步方法,是先发短息还是打电话? //先打电话 然后是发短信 这个是按时间来<br></br> */<br></br> public class Test2 {<br></br> public static void main(String[] args) throws InterruptedException {<br></br> //两个对象,两个调用者 两把锁<br></br> Phone2 phone1 = new Phone2();<br></br> Phone2 phone2 = new Phone2();<br></br> <br></br> //phone.sendSms(); 锁的问题<br></br> <br></br> new Thread(()->{<br></br> phone1.sendSms();<br></br> },"A").start();<br></br> <br></br> //捕获<br></br> <br></br> try {<br></br> TimeUnit.SECONDS.sleep(1);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> new Thread(()->{<br></br> phone2.call();<br></br> },"B").start();<br></br> <br></br> }<br></br> }<br></br> class Phone2{<br></br> //synchronized 锁的对象是方法的调用者 phone是锁<br></br> //两个方法(sendSms call)用的是同一个锁,谁先拿到谁执行<br></br> public synchronized void sendSms(){<br></br> try {<br></br> TimeUnit.SECONDS.sleep(4);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> System.out.println("发短信");<br></br> <br></br> }<br></br> public synchronized void call(){<br></br> System.out.println("打电话");<br></br> <br></br> }<br></br> <br></br> //这里没有锁!不是同步方法 不受锁的影响<br></br> public void hello(){<br></br> System.out.println("hello");<br></br> }<br></br> }<br></br>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.lock8;<br></br> <br></br> import java.util.concurrent.TimeUnit;<br></br> <br></br> /**<br></br> * 5增加两个静态的同步方法,只有一个对象,是先打印发短息还是先打印打电话?//先发短息后打电话<br></br> * 6.两个对象!增加两个静态的同步方法,是先发短息还是先打电话?//先发短息后打电话<br></br> */<br></br> public class Test3 {<br></br> public static void main(String[] args) throws InterruptedException {<br></br> //两个对象的Class类模板只有一个在加了static,锁的是Class<br></br> Phone3 phone1 = new Phone3();<br></br> Phone3 phone2 = new Phone3();<br></br> <br></br> <br></br> //phone.sendSms(); 锁的问题<br></br> <br></br> new Thread(()->{<br></br> phone1.sendSms();<br></br> },"A").start();<br></br> <br></br> //捕获<br></br> <br></br> try {<br></br> TimeUnit.SECONDS.sleep(1);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> new Thread(()->{<br></br> phone2.call();<br></br> },"B").start();<br></br> <br></br> }<br></br> }<br></br> //Phone3只有唯一的一个Class对象<br></br> // Class<Phone3> phone3Class = Phone3.class; 是全局唯一<br></br> //static走的是class对象 锁的是Class<br></br> class Phone3{<br></br> //synchronized 锁的对象是方法的调用者 phone是锁<br></br> //两个方法(sendSms call)用的是同一个锁,谁先拿到谁执行<br></br> //static静态方法 类一加载就有了 锁的是 Class 模板<br></br> public static synchronized void sendSms(){<br></br> try {<br></br> TimeUnit.SECONDS.sleep(4);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> System.out.println("发短信");<br></br> <br></br> <br></br> }<br></br> public static synchronized void call(){<br></br> System.out.println("打电话");<br></br> <br></br> }<br></br> <br></br> <br></br> }<br></br>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.lock8;<br></br> <br></br> import java.util.concurrent.TimeUnit;<br></br> <br></br> /**<br></br> * 1.一个静态的同步方法 一个普通的同步方法 只有一个对象 先打印发短息还是先打印打电话??//先打电话后发短息 因为锁的对象不同<br></br> *2.一个静态的同步方法 一个普通的同步方法 两个对象 先打印发短息还是先打印打电话??//先打电话后发短息<br></br> */<br></br> public class Test4 {<br></br> public static void main(String[] args) throws InterruptedException {<br></br> //两个对象的Class类模板只有一个在加了static,锁的是Class<br></br> Phone4 phone1 = new Phone4();<br></br> Phone4 phone2 = new Phone4();<br></br> <br></br> <br></br> <br></br> //phone.sendSms(); 锁的问题<br></br> <br></br> new Thread(()->{<br></br> phone1.sendSms();<br></br> },"A").start();<br></br> <br></br> //捕获<br></br> <br></br> try {<br></br> TimeUnit.SECONDS.sleep(1);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> new Thread(()->{<br></br> phone2.call();<br></br> },"B").start();<br></br> <br></br> }<br></br> }<br></br> //Phone3只有唯一的一个Class对象<br></br> // Class<Phone3> phone3Class = Phone3.class; 是全局唯一<br></br> //static走的是class对象 锁的是Class<br></br> class Phone4{<br></br> //静态的同步方法 锁的是Class类模板<br></br> public static synchronized void sendSms(){<br></br> try {<br></br> TimeUnit.SECONDS.sleep(4);<br></br> } catch (InterruptedException e) {<br></br> e.printStackTrace();<br></br> }<br></br> System.out.println("发短信");<br></br> <br></br> <br></br> }<br></br> //普通的同步方法 锁的是调用者<br></br> public static void call(){<br></br> System.out.println("打电话");<br></br> <br></br> }<br></br> <br></br> <br></br> <br></br> }<br></br>
小结
new this 具体的一个手机
static Class 唯一的一个模板
6 集合类不安全
List不安全
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded"> package com.kuang.unsafe;<br></br> <br></br> import java.util.*;<br></br> import java.util.concurrent.CopyOnWriteArrayList;<br></br> <br></br> //java.util.ConcurrentModificationException 并发修改异常<br></br> public class ListTest {<br></br> public static void main(String[] args) {<br></br> //并发下 ArrayList不安全 Synchronized<br></br> /**<br></br> * 解决方案<br></br> * 1.List<String> list = new Vector<>();<br></br> * 2. List<String> list = Collections.synchronizedList(new ArrayList<>());<br></br> * 3.List<String> list = new CopyOnWriteArrayList<>();<br></br> * CopyOnWriteArrayList 写入时复制 COW 计算机程序设计领域的一种优化策略<br></br> * 多个线程调用的时候,list是唯一的 读取的时候读取的是固定的,写入的时候可能存在后面写入的把前面的覆盖了<br></br> * CopyOnWriteArrayList 是在写入的时候避免覆盖,造成数据问题<br></br> *<br></br> * 读写分离<br></br> * CopyOnWriteArrayList比Vector的优点在哪?<br></br> */<br></br> <br></br> List<String> list = new CopyOnWriteArrayList<>();<br></br> for(int i = 1;i <=10;i++ ){<br></br> new Thread(()->{<br></br> list.add(UUID.randomUUID().toString().substring(0,5));<br></br> System.out.println(list);<br></br> },String.valueOf(i)).start();<br></br> <br></br> }<br></br> }<br></br> }<br></br>