1.多线程的实现

多线程有两种实现方式:

1.1.继承Thread类 =>示例:A a=new A(); a.start();

 

1.2.实现Runnable接口 =>示例:A a=new A(); new Thread(A,自定义线程名称).start();

 

其实Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式

获取当前线程名称:Thread.currentThread().getName()

调用线程是thread.start(),真正执行线程是 thread.run()

具体代码:

 /**
* 继承Thread类
* @date 2019/3/29 11:19
*/
public class SimpleThread extends Thread{ @Override
public void run() {
super.run();
Thread thread = Thread.currentThread();
System.out.println("Thread =>当前执行的线程为:"+thread.getName());
}
} /**
* 实现Runnable接口
* @date 2019/3/29 11:28
*/
public class SimpleRunnable implements Runnable { @Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println("Runnable =>当前执行的线程为:"+thread.getName());
}
} public class TestMain { /**执行线程示例1*/
private static void callSimpleThread(){
int index=10;
for (int i = 0; i < index; i++) {
Thread thread=new SimpleThread();
thread.start();
}
} /**执行线程示例1*/
private static void callSimpleRunnable(){
int index=10;
for (int i = 0; i < index; i++) {
SimpleRunnable simpleRunnable=new SimpleRunnable();
new Thread(simpleRunnable,"Runnable-"+i).start();
}
} public static void main(String[] args) { callSimpleThread(); callSimpleRunnable();
} }

2.多线程安全问题

2.1线程不安全示例

多线程最容易产生的一个问题就是线程安全问题,下面使用一个卖票的例子来体现。
场景描述:现在有两个售票员,一共卖10张车票
 public class SellTicket extends Thread {

     private static int NUMBER = 10;
public SellTicket(String name) {
super(name);
} @Override
public void run() {
String s = "线程:" + Thread.currentThread().getName(); while (NUMBER > 0) {
int i = NUMBER--;
System.out.println(s + " => 卖了第" + i + "号票");
} System.out.println(s + ",票已经卖完");
super.run();
} public static void main(String[] args) { SellTicket thread1 = new SellTicket("售票员A");
thread1.start(); SellTicket thread2 = new SellTicket("售票员B");
thread2.start(); } }

执行结果如下:

我们发现售票员A 和售票员B都卖了10号票,这就是线程不安全导致的结果

2.2线程不安全解决方法

方案一:使用同步代码解决
格式:synchronized(锁对象){需要被同步的代码}
锁对象可以为this锁,也可以自定义对象锁 方案二:使用同步函数解决
同步函数就是使用synchronized修饰一个函数

下面采用同步代码块解决

 public class SafetySellTicket extends Thread {

     private static int NUMBER = 10;

     @Override
public void run() {
String s = "线程:" + Thread.currentThread().getName(); while (NUMBER > 0) {
synchronized (this) {
if (NUMBER > 0) {
int i = NUMBER--;
System.out.println(s + " => 卖了第" + i + "号票");
} else {
System.out.println(s + ",票已经卖完");
break;
} }
}
super.run();
} public static void main(String[] args) { SafetySellTicket thread1 = new SafetySellTicket();
thread1.start(); SafetySellTicket thread2 = new SafetySellTicket();
thread2.start(); } }

【Java并发编程一】线程安全问题的更多相关文章

  1. Java并发编程基础-线程安全问题及JMM(volatile)

    什么情况下应该使用多线程 : 线程出现的目的是什么?解决进程中多任务的实时性问题?其实简单来说,也就是解决“阻塞”的问题,阻塞的意思就是程序运行到某个函数或过程后等待某些事件发生而暂时停止 CPU 占 ...

  2. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  3. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  4. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  5. Java并发编程:线程控制

    在上一篇文章中(Java并发编程:线程的基本状态)我们介绍了线程状态的 5 种基本状态以及线程的声明周期.这篇文章将深入讲解Java如何对线程进行状态控制,比如:如何将一个线程从一个状态转到另一个状态 ...

  6. Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  7. (转)Java并发编程:线程池的使用

    背景:线程池在面试时候经常遇到,反复出现的问题就是理解不深入,不能做到游刃有余.所以这篇博客是要深入总结线程池的使用. ThreadPoolExecutor的继承关系 线程池的原理 1.线程池状态(4 ...

  8. Java并发编程:线程池的使用(转载)

    转载自:https://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  9. Java并发编程:线程池的使用(转载)

    文章出处:http://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  10. [转]Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

随机推荐

  1. MySQL数据转移至SQL Server详解

    最近有个活是mysql数据转移到sql server 2012,直接手动转工作量太大,发现网上有工具教程,则记录一下. 一.安装MySQL ODBC驱动为MySQL安装Connector/ODBC驱动 ...

  2. Hadoop记录-切换NN

    一.第一种方法 重启namenode(1.1.1.1 1.1.1.2)重启standby节点:1.1hadoop-daemon.sh stop zkfchadoop-daemon.sh stop na ...

  3. ArcGis——好好的属性表,咋就乱码了呢?

    我就瞎说一下,反正你也不懂. ——见到许多ArcGis属性表乱码的问题,也见过各种哭笑不得的解说 目录 第一节 字符编码那些事儿→字符编码简述 第二节 都是编码惹的祸→ArcGis属性表出错原因 第三 ...

  4. Java虚拟机运行时内存区域简析

    figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...

  5. es6常用语法学习笔记

    1.let和const的常规使用 let声明的变量不存在预解析 let声明的变量不允许重复使用(在同一个作用域内) ES6引入了块级作用域{},块内部定义的变量,在外部是不可以访问到的 使用let在f ...

  6. SQL - for xml path('') 实现多行合并到一行, 并带有分隔符

    docs.microsoft.com 链接:  SQL一个应用场景与FOR XML PATH应用 首先呢!我们在增加一张学生表,列分别为(stuID,sName,hobby),stuID代表学生编号, ...

  7. ZOJ 3604 Tunnel Network(凯莱定理)

    题目链接: E - Tunnel Network ZOJ - 3604 题目大意: 给定编号1-n的点,和给定编号1-S 的联通图,刚开始1号联通图只有 1个顶点,就是编号为1的顶点,2号联通图也只有 ...

  8. OnePlus5刷机后一直检查更新

    大概是由于爱折腾,上一个手机是Nexus5,现在又是Oneplus5,闲来无事就爱刷机. 昨天看OnePlus官网的氧OS更新到Android9.0,于是又开启了刷机旅程. 显然这次没有之前那么顺利, ...

  9. 吴恩达《机器学习》课程笔记——第七章:Logistic回归

    上一篇  ※※※※※※※※  [回到目录]  ※※※※※※※※  下一篇 7.1 分类问题 本节内容:什么是分类 之前的章节介绍的都是回归问题,接下来是分类问题.所谓的分类问题是指输出变量为有限个离散 ...

  10. dos.orm的事务处理

    dos.orm也包含事务处理,没有太多封装,这里有几个简单的示例代码. using (DbTrans trans = DbSession.Default.BeginTransaction()) { D ...