上篇文章知识介绍了多线程的创建和启动问题,各个子线程和子线程或者说子线程和main线程没有信息的交流,这篇文章主要探讨线程之间信息共享以及交换问题。这篇文章主要以一个卖票例子来展开。

继承Thread重写run方法进行实现

初始代码:

public class Tickect1 {
public static void main(String[] args) { //创建四个线程进行测试
new Thread3().start();
new Thread3().start();
new Thread3().start();
new Thread3().start(); }
} class Thread3 extends Thread{
private static int tickets = 100;//总票数
@Override
public void run() {
while(true){
if(tickets<=0){
break;
}else{
System.out.println(Thread.currentThread().getName()+" "+tickets);
tickets--;
}
}
}
}

错误答案:卖了103张票

分析原因:1.类似于i++的操作不是原子操作





四个进程有四个工作缓存,每次都是修改工作缓存的数据,而且四个工作缓存之间的数据无法共享,倒置在缓存1中已经tickets-1,但是缓存2中tickets又无法获取1中缓存的数据所以票会增大,所以出现103

2.关键步骤缺少加锁操作(获取票数和对票数-1的操作同时执行会出现问题)



改进的代码:这个代码有bug,测试答案还是103

public class Tickect1 {
public static void main(String[] args) { //创建四个线程进行测试
new Thread3().start();
new Thread3().start();
new Thread3().start();
new Thread3().start(); }
} class Thread3 extends Thread{
private static volatile int tickets = 100;//总票数
@Override
public void run() {
while(true){
sale();
if(tickets<=0) break;
}
} public synchronized void sale(){//对数据修改进行加锁(同一时刻只能一个线程执行)
if(tickets>0){
System.out.println(Thread.currentThread().getName()+" "+tickets);
tickets--;
} }
}

实现Runnable的run方法进行实现

public class Ticket2 {
public static void main(String[] args) {
Thread4 t = new Thread4();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start(); }
} class Thread4 implements Runnable{ private volatile int tickets=100;//volatile起到通知各个线程缓存区的数据是否修改,如果修改就刷新缓冲区数据(变量副本的解决方法)
String str = new String("");//对这个对象加锁
@Override
public void run() {
while (true){
//sale();方式1
synchronized (str){//代码快加锁(方式2)
if(tickets>0){
System.out.println(Thread.currentThread().getName()+" "+tickets);
tickets--;
}
}
if(tickets<=0) break;
}
}
public synchronized void sale(){//synchronized对数据修改进行加锁(同一时刻只能一个线程执行)
if(tickets>0){//必须在这里判断,if放在外面会出现错误
System.out.println(Thread.currentThread().getName()+" "+tickets);
tickets--;
} }
}

volatile关键字测试

public class ThreadDemo2
{
public static void main(String args[]) throws Exception
{
TestThread2 t = new TestThread2();
t.start();
Thread.sleep(2000);
t.flag = false;
System.out.println("main thread is exiting");
}
} class TestThread2 extends Thread
{
//boolean flag = true; //子线程不会停止
volatile boolean flag = true; //用volatile修饰的变量可以及时在各线程里面通知
public void run()
{
int i=0;
while(flag)
{
i++;
}
System.out.println("test thread3 is exiting");
}
}

java多线程信息共享的更多相关文章

  1. JAVA多线程之间共享数据BlockingQueue介绍

    在JAVA的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利. ...

  2. java——多线程——内部类共享同一个外部类对象的成员变量

    public class Shop { public static void main(String[] args) { Outer o=new Outer(); Thread t1=o.getSal ...

  3. 循序渐进Java Socket网络编程(多客户端、信息共享、文件传输)

    目录[-] 一.TCP/IP协议 二.TCP与UDP 三.Socket是什么 四.Java中的Socket 五.基本的Client/Server程序 六.多客户端连接服务器 七.信息共享 八.文件传输 ...

  4. JAVA Socket(多个客户同时连接,信息共享) client (java/ruby)

    第一步 充分理解Socket 1.什么是socket 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字" ...

  5. Java多线程调试如何完成信息输出处理

    转载自:http://developer.51cto.com/art/201003/189078.htm Java多线程调试是很繁琐的,但是还是需要我们不断进行相关的学习.下面我们就来看看在Java多 ...

  6. Java多线程——查看线程堆栈信息

    Java多线程——查看线程堆栈信息 摘要:本文主要介绍了查看线程堆栈信息的方法. 使用Thread类的getAllStackTraces()方法 方法定义 可以看到getAllStackTraces( ...

  7. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  8. Java多线程干货系列—(一)Java多线程基础

    前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的 ...

  9. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

    概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...

随机推荐

  1. 2019-08-10 纪中NOIP模拟B组

    T1 [JZOJ1235] 洪水 题目描述 一天, 一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安全的. 森林的地图由R行C列组成,空白区域用点“.”表示,洪水的区域用“*”表示 ...

  2. 3ds Max File Format (Part 2: The first inner structures; DllDirectory, ClassDirectory3)

    Now that we understand the outer structure of the file, it's time to look closer to what's inside. T ...

  3. 基于alpine的php-fpm扩展swoole和pdo_mysql

    vim Dockerfile 插入一下内容 FROM php:fpm-alpine RUN echo http://mirrors.aliyun.com/alpine/v3.10/main>/e ...

  4. 【转】常见的hash算法及其原理

    Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是 ...

  5. Echart 地图实例

    1.地图实例 function func_InEchart() { require.config({ paths: { echarts: '../Scripts/echart2/echarts' }, ...

  6. PP: Composite visual mapping for time series visualization

    However: The conventional visual mapping maps each data attribute onto a single visual channel Purpo ...

  7. POJ3258 River Hopscotch(二分最大化最小值)

    题目链接:http://poj.org/problem?id=3258 题意:给n个石头,起点和终点也是两个石头,去掉这石头中的m个,使得石头间距的最小值最大. 思路:二分石头间的最短距离,每次贪心地 ...

  8. leetcode 925. Long Pressed Name

    判定是否长按 var isLongPressedName = function (name, typed) { var i = 1, j = 0, n = name.length, m = typed ...

  9. android 获取颜色 getColor 方法 deprecated 过期

    可以使用下面代码代替: ContextCompat.getColor(getContext(), R.color.post_list_content_color) 需要引入: compile 'com ...

  10. bitlocker对磁盘进行加密解密

    1,bitlocker是什么? BitLocker即Windows BitLocker驱动器加密.是微软在Windows Vista中新增的一种数据保护功能.使用BitLocker可以加密磁盘.主要用 ...