Java 线程安全

线程安全

  • 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
  • synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。
  • 当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法里的代码,首先是尝试获得锁,如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)

线程不安全

package com.example.core.safely;public class MyThread extends Thread{private int count = 5;public void run(){count--;System.out.println(this.currentThread().getName() + "count = "+count);}public static void main(String[] args) {MyThread my = new MyThread();Thread t1 = new Thread(my,"t1");Thread t2 = new Thread(my,"t2");Thread t3 = new Thread(my,"t3");Thread t4 = new Thread(my,"t4");Thread t5 = new Thread(my,"t5");t1.start();t2.start();t3.start();t4.start();t5.start();}
}

线程安全 -> 添加synchronized

  • synchronized 同步的概念就是共享,我们要牢牢记住"共享"这俩个字,如果不是共享的资源,就没有必要进行同步。
  • 异步:asynchronized 异步的概念就是独立,相互之间不受到任何制约。就好像我们学习http的时候,在页面发起的Ajax请求,我们还可以继续浏览或操作页面的内容,二者之间没有任何关系
  • 同步的目的就是为了线程安全,其实对于线程安全来说,需要满足俩个特性: 原子性(同步) 可见性    
package com.example.core.safely;public class MyThread extends Thread{private int count = 5;public synchronized void run(){count--;System.out.println(this.currentThread().getName() + "count = "+count);}public static void main(String[] args) {MyThread my = new MyThread();Thread t1 = new Thread(my,"t1");Thread t2 = new Thread(my,"t2");Thread t3 = new Thread(my,"t3");Thread t4 = new Thread(my,"t4");Thread t5 = new Thread(my,"t5");t1.start();t2.start();t3.start();t4.start();t5.start();}
}

线程之间的通信

  • 线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会使开发人员对线程任务在处理的过程中进行有效的把控与监督
  • 使用wait / notify 方法实现线程间的通信。(注意这两个方法都是object的类的方法,换句话说java为所有的对象都提供了这两个方法) wait 和 notify 必须配合 synchronized 关键字使用 wait方法释放锁notify方法不释放锁

ThreadLocal

  • 线程局部变量,是一种多线程间并发访问变量的解决方案。与其synchronized等加锁的方式不同,ThreadLocal完全不提供锁,而使用以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全
  • 从性能上说,ThreadLocal不具有绝对的优势,在并发不是很高的时候,加锁的性能会更好,但作为一套与锁完全无关的线程安全解决方案,在高并发量或者竞争激烈的场景,使用ThreadLocal可以在一定程度上减少锁竞争
package com.example.core.safely;public class UseThreadLocal {public static ThreadLocal<String> threadLocal = new ThreadLocal<>();public void setThreadLocal(String value){threadLocal.set(value);}public String getThreadLocal(){return threadLocal.get();}public static void main(String[] args) {UseThreadLocal utl = new UseThreadLocal();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {utl.setThreadLocal("张三");System.err.println("当前t1:"+utl.getThreadLocal());}},"t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {utl.setThreadLocal("李四");System.err.println("当前t2:"+utl.getThreadLocal());}},"t2");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}t1.start();t2.start();System.out.println("当前值"+utl.getThreadLocal());}
}

问题

  • 如题,有两个线程A、B,A线程向一个集合(List<String>) 里面依次添加元素“abc”字符串, 一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作,我们应该如何进行设计?

1,使用CountDownLatch

  • latch.countDown();//唤醒通知
  • latch.await();//阻塞
    
package com.example.core.safely;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class ListAdd2 {// 1 定义的承装字符串的容器private static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd2 list1 = new ListAdd2();final CountDownLatch latch = new CountDownLatch(1);//CountDownLatch让一个线程阻塞,另一个线程运行,(1)是通知的个数// 线程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {for(int i = 0; i <10; i++){list1.add();System.out.println("当前线程:" + Thread.currentThread().getName() + ", 添加了一个元素..");Thread.sleep(500);if(list.size() == 5) {System.err.println("已经发出了唤醒通知!");latch.countDown();//唤醒通知}}						} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 线程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){if(list1.size() != 5) {try {latch.await();//阻塞} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");throw new RuntimeException();}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

2,使用volalite关键字

package com.example.core.safely;import java.util.ArrayList;
import java.util.List;public class ListAdd3 {// 1 定义的承装字符串的容器private volatile static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd3 list1 = new ListAdd3();// 线程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {for(int i = 0; i <10; i++){list1.add();System.out.println("当前线程:" + Thread.currentThread().getName() + ", 添加了一个元素..");Thread.sleep(500);}						} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 线程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){if(list1.size() == 5){System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");throw new RuntimeException();}}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

3,使用synchronized配合使用wait和notify

package com.example.core.safely;import java.util.ArrayList;
import java.util.List;public class ListAdd1 {// 1 定义的承装字符串的容器private static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd1 list1 = new ListAdd1();final Object lock = new Object();// 线程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {synchronized (lock) {for(int i = 0; i <10; i++){list1.add();System.out.println("当前线程:" + Thread.currentThread().getName() + ", 添加了一个元素..");Thread.sleep(500);if(list.size() == 5) {System.err.println("已经发出了唤醒通知!");lock.notify();}}						}} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 线程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){synchronized (lock) {if(list1.size() != 5) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}//if(list1.size() == 5){System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");throw new RuntimeException();//}}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发者应该了解的API技术清单!

摘要&#xff1a;有人说&#xff0c;有API的地方就有App&#xff0c;借助这些API开发者轻松构建出一款应用&#xff0c;极大地提高开发效率和开发质量。文中整理了一份API服务清单&#xff0c;内容涵盖&#xff1a;监控/调试、 CDN 、数据库、仪表盘、支付、通信等方面&#xf…

提高程序员职场价值的10大技巧

如果你已经是个很牛叉的程序员&#xff0c;但是依然觉得觉得还不够的话&#xff0c;欢迎阅读此文。本文旨在帮助各位更上一层楼。 你是不是觉得自己已经掌握了所有的编程技巧&#xff1f;别太自以为是了&#xff01; 会写代码的确很重要&#xff0c;但是要拿到更好薪水&#…

google python的风格规范

点击链接&#xff0c;查看内容

IT人应当知道的10个行业小内幕

如果你打算从事IT行业或刚进入这个行业&#xff0c;也许本文下面的小内幕会吓到你&#xff0c;因为这些事平常都不会公开讨论的。如果你是IT资深人士&#xff0c;或许你已经遇到其中的大部分了。如果你愿意&#xff0c;请一起来参与讨论吧。 这些内幕大多数是针对网络管理员、…

Volatile原子性一致性JVM指令重排

概念 Volatile概念&#xff1a;Volatile关键字的主要作用是使变量在多个线程间可见。作用&#xff1a; 在多线程间可以进行变量的变更&#xff0c;使得线程间进行数据的共享可见 阻止指令重排序&#xff0c;happens-before package com.example.core.cas;import com.example.c…

python修改文件内容,不需要read,write多个动作。

python 要修改文件内容&#xff0c;常用 是先read&#xff0c;后write &#xff0c; 再 rename&#xff0c;很不爽。 比如&#xff1a;需要 把 yuv_dir "../HD/" # "H:/HD_Master/1080i25/" 改为 yuv_dir "C:/HD/" # "H:…

Atomic系列类

Atomic系列类别 Atomic系列类封装了一系列的基础类型和对象操作&#xff0c;其主要目的就是为了实现原子性&#xff0c;主要核心类如下 AtomicIntegerAtomicLongAtomicBooleanAtomicIntegerArrayAtomicLongArrayAtomicReference 原子性的引用对象在对Atomic类操作的时候&…

python 系统学习笔记(十二)---os os.path os.walk

得到当前工作目录&#xff0c;即当前 Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir()函数用来删除一个文件:os.remove()删除多个目录&#xff1a;os.removedirs&#xff08;r“c&#xff1a;\python”&#xff09;检验给出的路径是否是…

Java JUC工具类--CountDownLatch

CountDownLatch&#xff1a;用于监听某些初始化操作&#xff0c;并且线程进行阻塞&#xff0c;等初始化执行完毕后&#xff0c;通知主线程继续工作执行 package com.example.core.juc;import java.util.concurrent.CountDownLatch;public class UseCountDownLatch {public stat…

Java JUC工具类--CyclicBarrier

CyclicBarrier&#xff1a;栅栏的概念&#xff0c;多线程的进行阻塞&#xff0c;等待某一个临界值条件满足后&#xff0c;同时执行 类比&#xff1a;每个线程代表一个跑步运动员&#xff0c;当运动员都准备好后&#xff0c;才一起出发&#xff0c;只要有一个人没有准备好&#…

人生感悟:人生像吃自助餐

问我怎样管理欲望&#xff0c;过简单生活?我的答案是&#xff1a;你要先学会品味人生&#xff0c;品味的同义词&#xff0c;就叫做体悟内涵。 人为什么有这么多欲望?其实&#xff0c;我们每个人在一个社会&#xff0c;就像进入一个自助餐(buffet)店&#xff0c;食物非常的多…

Java JUC工具类--Future

Future模式&#xff0c;也是非常经典的设计模式&#xff0c;这种模式主要就利用空间换时间的概念&#xff0c;也就是说异步执行&#xff08;需要开启一个新的线程&#xff09;在互联网高并发的应用服务中&#xff0c;我们随处可见这种理念和代码&#xff0c;主要就是使用了这种…

职场与生活 八条原则 让你不再浪费时间和提高效率

Heidi Roizen女士一度是硅谷人人争相学习的典范。她曾创办自己的公司并管理了14年之久。后来&#xff0c;她担任苹果公司主管开发者关系的高级副总裁。现在&#xff0c;她是DFJ Venture的一位风投家&#xff0c;她还在斯坦福主讲一门名叫‌‌“企业家精神‌‌”的课程。她几乎认…

Java JUC工具类--Exchanger

Exchanger Exchanger用于进行线程间的数据交换&#xff0c;它提供一个同步点&#xff0c;在这个同步点&#xff0c;两个线程可以交换彼此的数据两个线程通过exchange方法交换数据&#xff0c;如果一个线程先执行exchange方法&#xff0c;它会一直等待第二个线程也执行exchang…

爸爸的素质决定孩子飞多高,爸爸们请反复看!!!

好父亲等于200个好老师&#xff0c;当爹的都好好看看&#xff0c;以后孩子不给力别怨别人! 孩子是父亲的影子&#xff0c;希望每个阅读完全文的父亲&#xff0c;都能成为一个好父亲。 NO.1爸爸是孩子最好的老师 爸爸的素质有多高&#xff0c;孩子就能飞多高 用理性的父爱帮…

Java JUC工具类--ForkJoin

ForkJoin Fork/Join框架是JAVA7提供的一个用于并行执行任务的框架&#xff0c;是一个把大任务分割成若干个小任务&#xff0c;最终汇总每个小任务结果后得到大任务结果的框架Fork/Join中两个重要的类 ForkJoinTask&#xff1a;使用该框架&#xff0c;需要创建一个ForkJoin任务…

修复bug的12个关键步骤

要多少时间才能修复bug&#xff0c;事先是很难知道的&#xff0c;特别是如果你和这些代码还素不相识的话&#xff0c;情况就更加扑朔迷离了。James Shore在《The Art of Agile 》一书中&#xff0c;明确指出要想修复问题得先知道问题的所在。而我们之所以无法准确估计时间是因为…

Java JUC工具类--Master-Worker

Master-Worker Master-Worker模式是常用的并行计算模式。它的核心思想是系统由两类进程协作工作&#xff1a;Master进程和Worker进程Master负责接收和分配任务&#xff0c;Worker负责处理子任务当各个Worker子进程处理完成后&#xff0c;会将结果返回给Master&#xff0c;由Ma…

身体打来的电话,你一定要接!

心脏有问题时。左边手臂会酸、麻、痛。肝脏有问题时。小腿晚上睡觉时容易抽筋。肾脏出现问题时。声音就会出不来&#xff0c;就会沙哑。脾胃出现问题时。偏头痛。附&#xff1a;五脏排毒最简单有效的方法 一、心脏有问题时 1。呼吸会不顺畅&#xff0c;胸口会闷也会刺痛&…