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 ...
随机推荐
- HADOOP中的CRC数据校验文件
Hadoop系统为了保证数据的一致性,会对文件生成相应的校验文件(.crc文件),并在读写的时候进行校验,确保数据的准确性.在本地find -name *.crc -print 看 比如我们遇到的这个 ...
- java时间操作
这篇讲的也很专业:http://soft.zdnet.com.cn/software_zone/2007/1129/660028.shtml java中的时间操作不外乎这四种情况: 1.获取当前时间 ...
- 关于C语言程序条件编译的简单使用方法
#include <stdio.h> #include <stdlib.h> #define Mode //如果定义了Mode,那么就执行这个函数 #ifdef Mode vo ...
- SpringBoot2.0之二 新建RESTfull风格项目
1.新建一个Maven项目(具体方法可以参照 SpringBoot之一) 2.先建一个User类 package com.somta.springboot.pojo; public class Use ...
- 关于web页面JApplet打印小票
版权所有 做这个的例子太少,我把我做的示例亮出来 一.先说说需要的版本 1.我用的浏览器只有ie: 火狐只支持52版本以下,并且是java7.java8.chrome不支持 2.applet客户端打印 ...
- oracle 随机数(转载)
http://blog.sina.com.cn/s/blog_6a01140c0100wimi.html 1.从表中随机取记录 select * from (select * from staff o ...
- python---内置函数,匿名函数,嵌套函数,高阶函数,序列化
函数简单说明 # 函数即"变量" # 高阶函数 # a.把一个函数名当做实参传给另一个函数(在不修改被装饰函数的源代码的情况下,为其添加功能) # b.返回值中包含函数名(不修改函 ...
- OSG嵌入QT(QT界面使用Qt Designer编辑)
本文主要内容:使用Qt Designer编辑好QT界面后,将OSG中的ViewerWidget嵌入到QT的Widget中. 在VS中嵌入QT工具,建立QT GUIApplication后,打开自动生成 ...
- HashMap原理浅析
HashMap概述 HashMap是基于哈希表和Map实现来的,它提供所有可选的映射方式,可以允许使用null键,除了不同步和允许使用null键之外,HashMap和HashTable基本上相同.因此 ...
- java之Spring(AOP)-Annotation实现添加切面
我们已经知道之前的切面添加方式(动态代理),是定义了一个实现了InvocationHandler接口的Handlerservice类,然后 在这个类内部写好切面逻辑,包括切面放置的位置,很显然下面的这 ...