码迷,mamicode.com
首页 > 编程语言 > 详细

java多线程信息共享

时间:2020-01-27 18:53:22      阅读:84      评论:0      收藏:0      [点我收藏+]

标签:string   原子操作   修改   ring   没有   ati   art   多线程   进程   

上篇文章知识介绍了多线程的创建和启动问题,各个子线程和子线程或者说子线程和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多线程信息共享

标签:string   原子操作   修改   ring   没有   ati   art   多线程   进程   

原文地址:https://www.cnblogs.com/cstdio1/p/12236400.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!