求助大神,关于对多线程的理解,有例子!

whereismymindM 2018-03-15 09:39:02
package ShangXueTangThread;

/**
* 方便共享资源
* @author Administrator
*
*/
public class Web12306Demo implements Runnable {
private int num =50;

@Override
public void run() {
while(true){
if(num<=0){
break; //跳出循环
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num);
num--;
}
}

public static void main(String[] args) {
//真实角色
Web12306Demo web = new Web12306Demo();
//代理
Thread t1 =new Thread(web,"路人甲");
Thread t2 =new Thread(web,"黄牛已");
Thread t3 =new Thread(web,"攻城师");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
上面这个例子,在打印的时候,出现了这样的情况,
攻城师抢到了3
攻城师抢到了2
攻城师抢到了1
黄牛已抢到了8
路人甲抢到了9
这个怎么理解,为什么会出现这种情况,帮忙看看我的理解有什么问题,请指正,多线程里,每个线程里的代码其实也是一行一行由上而下执行的,但是,比如线程一执行到第5行时,CPU暂停执行线程一,线程三开始执行,执行到三的第8行 ,三暂停,线程二执行,然后CPU开始执行线程一的第5行?但是我有个疑问,假设此时num=5,,线程一如果执行完while(true){
if(num<=0){
break; //跳出循环
}
,然后给暂停了,线程三开始执行完整一次循环,num=4,然后线程一再执行System.out.println(Thread.currentThread().getName()+"抢到了"+num);时,打印出来的num应该是5还是4?
...全文
801 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
空气中我最帅 2018-03-20
  • 打赏
  • 举报
回复
这个顺序混乱的话因为重排序还有线程的竞争,所以我们可以加锁(synchronized)来实现同步,对方法或者代码块进行加锁!
qq_37257058 2018-03-20
  • 打赏
  • 举报
回复
引用 4 楼 sinat_41605575 的回复:
[quote=引用 3 楼 qq_37257058 的回复:] num--操作不具有原子性,而且不加volatile或者锁 num变量在各自线程中运行也没有互见性
---------------------------------------------- 没有互见性是不是说,线程一对共享成员变量X=50的值减一,但是线程二并不知道此时X=49,以为还是50,所以线程二减一时还是X=49?[/quote] 对的,线程都有自己运行的内存空间
liyu93047 2018-03-19
  • 打赏
  • 举报
回复
高手啊 !!!
菊花超人 2018-03-19
  • 打赏
  • 举报
回复
引用 6 楼 sinat_41605575 的回复:
[quote=引用 5 楼 qq_28893679 的回复:] /* * 文件名:ThreadTest.java 版权:©Copyright by www.chaoyue-tech.cn 描述: 修改人:Administrator 修改时间:2018年3月17日 * 修改内容: */ public class ThreadOne implements Runnable { private int num = 50; @Override public void run() { while (true) { synchronized (this) { if (num <= 0) { break; // 跳出循环 } System.out.println(Thread.currentThread().getName() + "抢到了" + num); num-- ; } } } public static void main(String[] args) { // 真实角色 ThreadOne web = new ThreadOne(); // 代理 Thread t1 = new Thread(web, "路人甲"); Thread t2 = new Thread(web, "黄牛已"); Thread t3 = new Thread(web, "攻城师"); // 启动线程 t1.start(); t2.start(); t3.start(); } } 其实我觉得真正的代码应该是这样写的,需要使用到synchoronized来锁住this这个对象,这个this代表的可能是黄牛或工程师对象等。这样只有这个对象释放了,下一个对象才能获取到锁(你可以把这个现象类比为成语接龙,如果一个一个来,游戏就能玩下去,但是如果同时多个人来接龙,就会出现顺序混乱)
------------------------------------ 应该是我没表达好,加锁synchoronized来锁住this这个对象我知道,视频里有解释 我不明白的是,没锁的话,为什么比如说前面都是正常排序,就42张,43张排到了最后,按道理讲,前面那些操作不都是对剩余票修改了,就算因为线程原因延迟,但是怎么会排到这么后? [/quote] ---------------------------------------- 你的输出system.out 也没上锁 输出num之前也有竞态关系,所以输出就出现了你说的 输出排序混乱
whereismymindM 2018-03-18
  • 打赏
  • 举报
回复
引用 5 楼 qq_28893679 的回复:
/* * 文件名:ThreadTest.java 版权:©Copyright by www.chaoyue-tech.cn 描述: 修改人:Administrator 修改时间:2018年3月17日 * 修改内容: */ public class ThreadOne implements Runnable { private int num = 50; @Override public void run() { while (true) { synchronized (this) { if (num <= 0) { break; // 跳出循环 } System.out.println(Thread.currentThread().getName() + "抢到了" + num); num-- ; } } } public static void main(String[] args) { // 真实角色 ThreadOne web = new ThreadOne(); // 代理 Thread t1 = new Thread(web, "路人甲"); Thread t2 = new Thread(web, "黄牛已"); Thread t3 = new Thread(web, "攻城师"); // 启动线程 t1.start(); t2.start(); t3.start(); } } 其实我觉得真正的代码应该是这样写的,需要使用到synchoronized来锁住this这个对象,这个this代表的可能是黄牛或工程师对象等。这样只有这个对象释放了,下一个对象才能获取到锁(你可以把这个现象类比为成语接龙,如果一个一个来,游戏就能玩下去,但是如果同时多个人来接龙,就会出现顺序混乱)
------------------------------------ 应该是我没表达好,加锁synchoronized来锁住this这个对象我知道,视频里有解释 我不明白的是,没锁的话,为什么比如说前面都是正常排序,就42张,43张排到了最后,按道理讲,前面那些操作不都是对剩余票修改了,就算因为线程原因延迟,但是怎么会排到这么后?
  • 打赏
  • 举报
回复
/* * 文件名:ThreadTest.java 版权:©Copyright by www.chaoyue-tech.cn 描述: 修改人:Administrator 修改时间:2018年3月17日 * 修改内容: */ public class ThreadOne implements Runnable { private int num = 50; @Override public void run() { while (true) { synchronized (this) { if (num <= 0) { break; // 跳出循环 } System.out.println(Thread.currentThread().getName() + "抢到了" + num); num-- ; } } } public static void main(String[] args) { // 真实角色 ThreadOne web = new ThreadOne(); // 代理 Thread t1 = new Thread(web, "路人甲"); Thread t2 = new Thread(web, "黄牛已"); Thread t3 = new Thread(web, "攻城师"); // 启动线程 t1.start(); t2.start(); t3.start(); } } 其实我觉得真正的代码应该是这样写的,需要使用到synchoronized来锁住this这个对象,这个this代表的可能是黄牛或工程师对象等。这样只有这个对象释放了,下一个对象才能获取到锁(你可以把这个现象类比为成语接龙,如果一个一个来,游戏就能玩下去,但是如果同时多个人来接龙,就会出现顺序混乱)
whereismymindM 2018-03-17
  • 打赏
  • 举报
回复
引用 3 楼 qq_37257058 的回复:
num--操作不具有原子性,而且不加volatile或者锁 num变量在各自线程中运行也没有互见性
---------------------------------------------- 没有互见性是不是说,线程一对共享成员变量X=50的值减一,但是线程二并不知道此时X=49,以为还是50,所以线程二减一时还是X=49?
qq_37257058 2018-03-16
  • 打赏
  • 举报
回复
num--操作不具有原子性,而且不加volatile或者锁 num变量在各自线程中运行也没有互见性
whereismymindM 2018-03-15
  • 打赏
  • 举报
回复
引用 1 楼 oh_Maxy 的回复:
对共享资源num的判断和计算,要加锁:

    private int num = 50;
    private Object locker = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (locker) {
                if (num <= 0) {
                    break; // 跳出循环
                }
                System.out.println(Thread.currentThread().getName() + "抢到了" + num);
                num--;
            }
        }
    }
-------------------------------------- 我也知道要加锁,我不理解的是,不加锁的情况下,有时候会出现几个线程拿到同一张票的额情况,比如都是拿到了第43张,有的情况是前面顺序都很正常,就是在末尾出现了抢到19,17这类的情况!今天找了一天资料了,只知道原来这叫竞争条件,还跟主内存,线程的运行内存有关,但是太笼统了,感觉脑子好乱!
oh_Maxy 2018-03-15
  • 打赏
  • 举报
回复
对共享资源num的判断和计算,要加锁:

    private int num = 50;
    private Object locker = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (locker) {
                if (num <= 0) {
                    break; // 跳出循环
                }
                System.out.println(Thread.currentThread().getName() + "抢到了" + num);
                num--;
            }
        }
    }

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧