java多线程及线程安全详解
为什么要使用多线程:
单线程只能干一件事 而多线程可以同时干好多事(将任务放到线程里执行 效率高)
而所谓同时干并不是真正意义上的同时 只是(这里就叫CPU)cpu在每个线程中随机切换来执行 线程中要干的活
多线程编写:
1)第一种:(线程类)
class Stu1 extends Thread{
//重写 run方法
}
调用:Stu1 su = new Stu1();
su.start()//内部会自动调用run方法 把run方法放到线程上调用
2)第二种:普通任务类(由于第一种类只能是单继承 就没法实现继承其他父类并且继承线程类 所以第一种方法扩展性比较差)
直接创建线程对象 线程内干的事 放到一个自定义对象里面实现 (用到修饰设计模式)
底层代码
class Thread{
private Runnable r
public void Thread(Runnable r){ //利用有参构造将自定义对象传进来
this.r = r;
}
public void start(){
r.run();
}
}
class Stu implements Runnable{} 通过实现接口 线程类底层start调用的run方法 实际就是我们自定义类中的run方法
Thread th = new Thread(new Stu()) //直接创建线程对象
th.start();
我们用第二种方法创建多线程如下:
public static void main(String[] args) {
// 不同线程干同一件事
SaleWindow sw = new SaleWindow();
Thread t1 = new Thread(sw);
Thread t2 = new Thread(sw);
t1.setName("窗口A");
t2.setName("窗口B");
t1.start();
t2.start();
}
public class SaleWindow implements Runnable {
private int ticketCount = 10; @Override
public void run() {
// TODO Auto-generated method stub
// 多个窗口卖票
for(int i = 0;i<10;i++){
if(ticketCount>0){
//字符串拼接信息 变量+"" 就可以拼接成字符串
System.out.println(Thread.currentThread().getName()+"卖出"+ticketCount+"张票");
ticketCount--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
} }
最后结果图:
从运行结果来看:同一张票卖给了二个人 这是在现实生活中不允许的 这样就会产生线程安全问题。
而产生线程安全问题的有三个要素必须同时满足才会产生线程安全:
1、必须有共享资源
2、必须是多线程环境
3、每个线程都适用了共享资源
而上面的例子:票是共享资源、又是多线程环境、线程执行任务的时候又使用了共享资源 所以会产生线程安全
怎么解决线程安全?
解决线程安全其核心:就是将某一个线程中的任务给锁(同步锁)起来,这个时候JVM就不得不等到本任务里的代码执行完以后在去执行另外一个线程里的任务。
(ps:在没加同步锁时jvm可以随时在线程之间随机切换,很有可能本线程的任务没有执行完就切换到别的线程上去了)
二种方法:
1、同步代码块:
public class SaleWindow implements Runnable {
private int ticketCount = 10; @Override
public void run() {
// TODO Auto-generated method stub
// 多个窗口卖票
for (int i = 0; i < 10; i++) {//可以随意设置锁
synchronized (this) {
if (ticketCount > 0) {
// 字符串拼接信息 变量+"" 就可以拼接成字符串
System.out.println(Thread.currentThread().getName() + "卖出"
+ ticketCount + "张票");
ticketCount--;
try {
Thread.sleep(500);//每隔500毫秒 线程休眠 随后自己自动会唤醒(目的是为了调节线程速度)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
}
} }
2、同步方法:
public class SaleWindow implements Runnable {
private int ticketCount = 10;
//默认固定的锁对象this
//将产生线程安全的代码封装到方法里并设置成同步方法
public synchronized void syncB() {
if (ticketCount > 0) {
// 字符串拼接信息 变量+"" 就可以拼接成字符串
System.out.println(Thread.currentThread().getName() + "卖出"
+ ticketCount + "张票");
ticketCount--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
} @Override
public void run() {
// TODO Auto-generated method stub
// 多个窗口卖票
for (int i = 0; i < 10; i++) {
syncB();
}
} }
结果图:
最后结果每个窗口不能卖同样的票解决了线程安全问题
线程之间的通信
(ps:线程之间的通信和线程安全无关联二者不是一回事)
怎样才能让二个线程之间进行通信?
线程之间是相互独立的互不联系 而真正意义上的通信是通过中间件(同步锁 必须是同一把锁)来达到线程之间通信的目的
案例:二个线程来回交替输出一条数据(意思就是必须按照我说一句你说一句的这个规则走)
class BingB extends Thread {
public void run(){
for(int i = 0;i<5;i++){
System.out.println("冰冰美,如花丑");
}
}
} class RuH extends Thread{
public void run(){
for(int i = 0;i<5;i++){
System.out.println("如花美,冰冰丑");
}
}
} public class Test {
public static void main(String[] args) {
BingB bb = new BingB();
RuH rh = new RuH();
bb.start();
rh.start();
}
}
结果图:此结果不是交替出现的
要想达到交替的目的代码如下:
class MyLock{
static Object o = new Object();
} class BingB extends Thread {
public void run(){
for(int i = 0;i<5;i++){
//加锁(意思是必须等到本线程的任务代码执行完以后才去执行别的线程的代码)
synchronized (MyLock.o) {
System.out.println("冰冰美,如花丑");
MyLock.o.notify();//唤醒另一个线程(这里表示如花线程)
try {
MyLock.o.wait();//暂时彻底休眠本线程(不会自动唤醒 需要手动唤醒) 同时解锁 阻塞线程 代码就不会往下继续走 jvm会切换到另外一个线程中去
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
}
}
}
} class RuH extends Thread{
public void run(){
for(int i = 0;i<5;i++){
synchronized (MyLock.o) {
System.out.println("如花美,冰冰丑");
MyLock.o.notify();//唤醒另一个线程(这里表示如冰冰程)
try {
MyLock.o.wait();//暂时彻底休眠本线程 同时解锁 阻塞线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
} public class Test {
public static void main(String[] args) {
BingB bb = new BingB();
RuH rh = new RuH();
bb.start();
rh.start();
}
}
从以上例子可以看出产生线程安全并解决线程安全 到实现线程间的通信 都用到了 同步锁 所以 同步锁既可以解决线程安全问题 又可以解决线程之间的通信
多线程状态流程图:
写到这里有关线程的基本讲解完毕,如果内容有我自己理解错误的地方还请各位大神指教,小弟不吝求教!
java多线程及线程安全详解的更多相关文章
- Java多线程之线程池详解
前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...
- JAVA多线程Thread VS Runnable详解
要求 必备知识 本文要求基本了解JAVA编程知识. 开发环境 windows 7/EditPlus 演示地址 源文件 进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也 ...
- Java 并发编程 | 线程池详解
原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...
- Java面试问题——线程全面详解总结
一.多线程是什么?为什么要用多线程? 介绍多线程之前要介绍线程,介绍线程则离不开进程. 首先进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元: ...
- java多线程环境单例模式实现详解
Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...
- Java 多线程同步和异步详解
java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...
- java多线程——同步块synchronized详解
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...
- Java同步之线程池详解
带着问题阅读 1.什么是池化,池化能带来什么好处 2.如何设计一个资源池 3.Java的线程池如何使用,Java提供了哪些内置线程池 4.线程池使用有哪些注意事项 池化技术 池化思想介绍 池化思想是将 ...
- Java多线程中join方法详解
join()方法用于让当前执行线程等待join线程执行结束.其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待. join()方法部分实现细节 while(isAli ...
随机推荐
- 滑动UITableViewCell出现多个按钮
iOS > = 5.0使用第三方效果图 iOS> = 8.0使用系统方法效果图 MGSwipeTableCell(Github上的三方库)- iOS >= 5.0 直接使用比较简单 ...
- ERP-非财务人员的财务培训教(一.二)------财务基础知识
二.基本财务管理知识 第一节 财务管理基础知识(一) 财务与会计的关系 会计的基础知识 (一) 财务与会计的关系 财务与会计的内涵 1.会计 会计工作主要是解决三个环节的问题: 会计凭证 会计账簿 会 ...
- Android开发技巧——自定义单选或多选的ListView
这篇其实应该是属于写自定义单选或多选的ListView的基础教程,无奈目前许多人对此的实现大多都绕了远路,反而使得这正规的写法倒显得有些技巧性了. 本文原创,转载请注明在CSDN上的出处: http: ...
- Spring--ClassPathResource
/* * 用一个给定的类加载器或者给定的类来加载资源 */ public class ClassPathResource extends AbstractFileResolvingResource { ...
- kettle 的表输出 table output
kettle的表输出: 双击后,看设置, 1,在connecttion后面,点击new里新建一个.设定各个选项值,如选择mysql类型,则配置hostname,database name,端口, 用户 ...
- LESS学习笔记 —— 入门
今天在网上完成了LESS的基础学习,下面是我的学习笔记.总共有三个文件:index.html.main.less.mian.css,其中 mian.css 是 main.less 经过Koala编译之 ...
- Java IO学习--(四)网络
Java中网络的内容或多或少的超出了Java IO的范畴.关于Java网络更多的是在我的Java网络教程中探讨.但是既然网络是一个常见的数据来源以及数据流目的地,并且因为你使用Java IO的API通 ...
- jquery左右折叠框
网站左右折叠框: <!DOCTYPE html> <html> <style> #Kefclose,#Kefopen{position:absolute;left: ...
- 教你一步步发布一个开源库到 JCenter
今天想来分享下,如何一步步自己发布一个开源库到 JCenter 这方面的博客网上已经特别多了,所以本篇并不打算仅仅只是记录流程步骤而已,而是尽可能讲清楚,为什么需要有这个步骤,让大伙知其然的同时还知其 ...
- Zookeeper简介和安装(二)
一.简介: Zookeeper是一个分布式协调服务,提供的服务如下: 命名服务:类似于DNS,但仅对于节点 配置管理:服务配置信息的管理 集群管理:Dubbo使用Zookeeper实现服务治理 分布式 ...