zoukankan      html  css  js  c++  java
  • java多线程信息共享

    上篇文章知识介绍了多线程的创建和启动问题,各个子线程和子线程或者说子线程和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");
    	}	
    } 
    
    不一样的烟火
  • 相关阅读:
    js 日期插件 datepicker
    Yii 安装二维码扩展Qrcode
    Yii2 验证码
    Yii 通过composer 安装的方法
    JQery icheck 插件
    Yii 设置 flash消息 创建一个渐隐形式的消息框
    Yii2 自动更新时间created_at updated_at
    MySQL 安装与使用(二)
    MySQL 安装与使用(一)
    Nginx使用(配置开机启动)
  • 原文地址:https://www.cnblogs.com/cstdio1/p/12236400.html
Copyright © 2011-2022 走看看