原文地址:http://blog.csdn.net/hejingyuan6/article/details/47053409#

多线程共享数据的方式:

1,如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做。

2,如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计4个线程。其中两个线程每次对j增加1,另外两个线程对j每次减1,银行存取款

 

有两种方法来解决此类问题:

将共享数据封装成另外一个对象,然后将这个对象逐一传递给各个Runnable对象,每个线程对共享数据的操作方法也分配到那个对象身上完成,这样容易实现针对数据进行各个操作的互斥和通信

将Runnable对象作为一个类的内部类,共享数据作为这个类的成员变量,每个线程对共享数据的操作方法也封装在外部类,以便实现对数据的各个操作的同步和互斥,作为内部类的各个Runnable对象调用外部类的这些方法。

每个线程执行的代码相同,可以使用同一个Runnable对象

卖票系统demo:

package com.xujishou;

public class SellTicket {
/**
* @param args
*/
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(t).start();
new Thread(t).start();
}
} class Ticket implements Runnable { private int ticket = 10; public void run() {
while (ticket > 0) {
ticket--;
System.out.println("当前票数为:" + ticket);
} }
}

执行

简单的多线程间数据共享,每个线程执行的代码不同,用不同的Runnable对象

设计4个线程。

其中两个线程每次对j增加1,另外两个线程对j每次减1

package com.xujishou;

public class TestThread {
/**
* @param args
*/
public static void main(String[] args) {
final MyData data = new MyData();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() { public void run() {
data.add(); } }).start();
new Thread(new Runnable() { public void run() {
data.dec(); } }).start();
}
} } class MyData {
private int j = 0; public synchronized void add() {
j++;
System.out.println("线程" + Thread.currentThread().getName() + "j为:" + j);
} public synchronized void dec() {
j--;
System.out.println("线程" + Thread.currentThread().getName() + "j为:" + j);
} }

银行存取款实例:

package com.xujishou;

public class Acount {

    private int money;

    public Acount(int money) {
this.money = money;
} public synchronized void getMoney(int money) {
// 注意这个地方必须用while循环,因为即便再存入钱也有可能比取的要少
while (this.money < money) {
System.out.println("取款:" + money + " 余额:" + this.money
+ " 余额不足,正在等待存款......");
try {
wait();
} catch (Exception e) {
}
}
this.money = this.money - money;
System.out.println("取出:" + money + " 还剩余:" + this.money); } public synchronized void setMoney(int money) { try {
Thread.sleep(10);
} catch (Exception e) {
}
this.money = this.money + money;
System.out.println("新存入:" + money + " 共计:" + this.money);
notify();
} public static void main(String args[]) {
Acount Acount = new Acount(0);
Bank b = new Bank(Acount);
Consumer c = new Consumer(Acount);
new Thread(b).start();
new Thread(c).start();
}
} // 存款类
class Bank implements Runnable {
Acount Acount; public Bank(Acount Acount) {
this.Acount = Acount;
} public void run() {
while (true) {
int temp = (int) (Math.random() * 1000);
Acount.setMoney(temp);
}
} } // 取款类
class Consumer implements Runnable {
Acount Acount; public Consumer(Acount Acount) {
this.Acount = Acount;
} public void run() {
while (true) {
int temp = (int) (Math.random() * 1000);
Acount.getMoney(temp);
}
}
}

  

总结:

其实多线程间的共享数据最主要的还是互斥,多个线程共享一个变量,针对变量的操作实现原子性即可。

原文地址:http://blog.csdn.net/hejingyuan6/article/details/47053409#

多线程共享数据的方式:

1,如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做。

2,如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计4个线程。其中两个线程每次对j增加1,另外两个线程对j每次减1,银行存取款

 

有两种方法来解决此类问题:

将共享数据封装成另外一个对象,然后将这个对象逐一传递给各个Runnable对象,每个线程对共享数据的操作方法也分配到那个对象身上完成,这样容易实现针对数据进行各个操作的互斥和通信

将Runnable对象作为一个类的内部类,共享数据作为这个类的成员变量,每个线程对共享数据的操作方法也封装在外部类,以便实现对数据的各个操作的同步和互斥,作为内部类的各个Runnable对象调用外部类的这些方法。

下面逐一介绍

每个线程执行的代码相同,可以使用同一个Runnable对象

卖票系统demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.xujishou;
 
public class SellTicket {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(t).start();
        new Thread(t).start();
    }
}
 
class Ticket implements Runnable {
 
    private int ticket = 10;
 
    public void run() {
        while (ticket > 0) {
            ticket--;
            System.out.println("当前票数为:" + ticket);
        }
 
    }
}

执行

简单的多线程间数据共享,每个线程执行的代码不同,用不同的Runnable对象

设计4个线程。

其中两个线程每次对j增加1,另外两个线程对j每次减1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.xujishou;
 
public class TestThread {
    /**
     * @param args
     */
    public static void main(String[] args) {
        final MyData data = new MyData();
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
 
                public void run() {
                    data.add();
 
                }
 
            }).start();
            new Thread(new Runnable() {
 
                public void run() {
                    data.dec();
 
                }
 
            }).start();
        }
    }
 
}
 
class MyData {
    private int j = 0;
 
    public synchronized void add() {
        j++;
        System.out.println("线程" + Thread.currentThread().getName() + "j为:" + j);
    }
 
    public synchronized void dec() {
        j--;
        System.out.println("线程" + Thread.currentThread().getName() + "j为:" + j);
    }
 
}

银行存取款实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package com.xujishou;
 
public class Acount {
 
    private int money;
 
    public Acount(int money) {
        this.money = money;
    }
 
    public synchronized void getMoney(int money) {
        // 注意这个地方必须用while循环,因为即便再存入钱也有可能比取的要少
        while (this.money < money) {
            System.out.println("取款:" + money + " 余额:" this.money
                    " 余额不足,正在等待存款......");
            try {
                wait();
            catch (Exception e) {
            }
        }
        this.money = this.money - money;
        System.out.println("取出:" + money + " 还剩余:" this.money);
 
    }
 
    public synchronized void setMoney(int money) {
 
        try {
            Thread.sleep(10);
        catch (Exception e) {
        }
        this.money = this.money + money;
        System.out.println("新存入:" + money + " 共计:" this.money);
        notify();
    }
 
    public static void main(String args[]) {
        Acount Acount = new Acount(0);
        Bank b = new Bank(Acount);
        Consumer c = new Consumer(Acount);
        new Thread(b).start();
        new Thread(c).start();
    }
}
 
// 存款类
class Bank implements Runnable {
    Acount Acount;
 
    public Bank(Acount Acount) {
        this.Acount = Acount;
    }
 
    public void run() {
        while (true) {
            int temp = (int) (Math.random() * 1000);
            Acount.setMoney(temp);
        }
    }
 
}
 
// 取款类
class Consumer implements Runnable {
    Acount Acount;
 
    public Consumer(Acount Acount) {
        this.Acount = Acount;
    }
 
    public void run() {
        while (true) {
            int temp = (int) (Math.random() * 1000);
            Acount.getMoney(temp);
        }
    }
}

  

总结:

其实多线程间的共享数据最主要的还是互斥,多个线程共享一个变量,针对变量的操作实现原子性即可。

JAVA 并发编程-多个线程之间共享数据的更多相关文章

  1. JAVA 并发编程-多个线程之间共享数据(六)

    多线程共享数据的方式: 1.假设每一个线程运行的代码同样.能够使用同一个Runnable对象,这个Runnable对象中有那个共享数据,比如,卖票系统就能够这么做. 2,假设每一个线程运行的代码不同. ...

  2. 【转】JAVA 并发编程-多个线程之间共享数据

    原文地址:http://blog.csdn.net/hejingyuan6/article/details/47053409# 多线程共享数据的方式: 1,如果每个线程执行的代码相同,可以使用同一个R ...

  3. Java并发编程--6.Exchanger线程间交换数据

    在两个线程之间定义同步点,当两个线程都到达同步点时,他们交换数据结构,因此第一个线程的数据结构进入到第二个线程中,第二个线程的数据结构进入到第一个线程中 在生产者-消费者情境模式中它包含了一个数缓冲区 ...

  4. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  5. 【Java并发编程一】线程安全和共享对象

    一.什么是线程安全 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的 ...

  6. Java并发编程实战 之 对象的共享

    上一篇介绍了如何通过同步多个线程避免同一时刻访问相同数据,本篇介绍如何共享和发布对象,使它们被安全地由多个进程访问. 1.可见性 通常,我们无法保证执行读操作的线程能看到其他线程写入的值,因为每个线程 ...

  7. 【java并发编程实战】-----线程基本概念

    学习Java并发已经有一个多月了,感觉有些东西学习一会儿了就会忘记,做了一些笔记但是不系统,对于Java并发这么大的"系统",需要自己好好总结.整理才能征服它.希望同仁们一起来学习 ...

  8. Java并发编程扩展(线程通信、线程池)

    之前我说过,实现多线程的方式有4种,但是之前的文章中,我只介绍了两种,那么下面这两种,可以了解了解,不懂没关系. 之前的文章-->Java并发编程之多线程 使用ExecutorService.C ...

  9. Java并发编程:进程和线程的由来(转)

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

随机推荐

  1. MySQL触发器的正确使用与案例分析

    以下的文章主要向大家讲述的是MySQL触发器的实际使用详细说明与实际案例分析,同时本文也列举了一些在MySQL触发器的实际式操作中的代码,以下就是文章的详细内容介绍,望大家借鉴. 触发器案例 mysq ...

  2. LibreOJ#6030. 「雅礼集训 2017 Day1」矩阵

    https://loj.ac/problem/6030 如果矩阵第i列有一个黑色, 那可以用他把第i行全都染黑,也可以使任意一列具有黑色 然后就可以用第i行把矩阵染黑 染黑一列的代价最少是1 染黑一行 ...

  3. seaborn基础整理

    seaborn是基于matplotlib的更高级的做图工具,下面主要针对以下几个部分进行整理: 第一部分:https://douzujun.github.io/page/%E6%95%B0%E6%8D ...

  4. Qt_扫雷游戏实现

    源代码下载(详细注释): 详细代码(注释): https://github.com/xiaocangtian/GameMine 链接: http://pan.baidu.com/s/1gf9Ux5h ...

  5. 【学习DIV+CSS】2. 学习CSS(一)--CSS控制页面样式

    1. CSS如何控制页面 使用XHTML+CSS布局页面,其中有一个很重要的特点就是“结构与表现相分离”(结构指XHTML,表现指CSS).有人这样描述这种分离的关系,结构XHTML好比一个人,表现C ...

  6. 视差滚动(Parallax Scrolling)的一点小心得

    下面内容来源于我知乎的这个答案:http://www.zhihu.com/question/20990029/answer/21436067 假期有空,整理到博客园这边,并做了一些语境的调整. ——— ...

  7. 2017 ACM暑期多校联合训练 - Team 9 1008 HDU 6168 Numbers (模拟)

    题目链接 Problem Description zk has n numbers a1,a2,...,an. For each (i,j) satisfying 1≤i<j≤n, zk gen ...

  8. 防止 Google Smart Lock 记忆错的用户名

    默认 chrome 会查找密码上面的那个(非隐藏非禁用)的表单域 如果上面是个短信验证码框,就会将验证码当成用户名提示用户保存. 在用户名 input 上添加 autocomplete="u ...

  9. 20165320 Java实验三:敏捷开发与XP实践

    实验内容: 敏捷开发与XP实践 一 实验要求: 安装alibaba 插件,解决代码中的规范问题在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Co ...

  10. Java设计模式——工厂模式

    一.工厂模式分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类: (1)简单工厂模式(Simp ...