zoukankan      html  css  js  c++  java
  • 什么是java的线程安全?同步,异步

    线程是比进程更小的执行单位,是在进程基础上进行的进一步划分。所谓多线程是指进程在执行过程中可以产生多个同时存在、同时运行的线程。多进程机制可以合理利用资源,提高程序的运行效率。一个进程至少包含一个线程(JVM虚拟机的启动是多线程的,至少有两个线程:main 和垃圾回收机制)。

    1、什么是线程安全?

    进程在运行时为了更好的利用资源提高运行效率,会产生多个线程,但是这多个线程运行时,会对同一个资源同时进行操作,也称之为线程异步,例如:线程A,B在对同一个链表进行操作时,如果出现了A对链表进行读取的同时,线程B同时对其进行写入数据。显然这样是非常不好的。那么就需要线程同步。

    2、何为线程同步?

    线程同步:通俗而言就是,当线程A在对某一资源进行操作时,那么线程B以及其他线程就必须等待,此时不能对这一资源进行操作。即线程A、B按照预定的计划对这一资源进行非同时访问。

    3、线程安全:对于线程异步,这样的线程在运行时是不安全的,所以就引进同步。

    //java中实现多线程有两种方法,继承自Thread类,实现Runnable接口。
    //1 继承自Thread接口需要实现run方法,
    public class  ThreadDemo extends Thread{
        private String name;
        public ThreadDemo(String name){
            this.name=name;
        }
        //重写Thread类中的run方法
        public void run(){
            for(int i=0;i<=10;i++){
                System.out.println(name+"运行i="+i);
            }
        }
        public static void main(String [] name){
            new ThreadDemo("线程A").start();
            new ThreadDemo("线程B").start();
        }
    }
    结果证明:线程A,B交错运行。

    public class RunnableDemo implements Runnable{
        private String name;
        public RunnableDemo(String name){
            this.name=name;
        }
        @Override
        public void run() {
            for(int i=1;i<=15;i++){
                System.out.println(name+"运行i="+i);
            }
            
        }  
        public static void main(String [] args){
            RunnableDemo demo1=new RunnableDemo("线程A");
            RunnableDemo demo2=new RunnableDemo("线程B");
            Thread thread1=new Thread(demo1);//实例化Thread类
            Thread thread2=new Thread(demo2);//实例化Thread类
            thread1.start();//启动线程
            thread2.start();//启动线程
        }
    }
    //注意启动多线程必须使用Thread类实现

    Thread类与Runnable接口的区别,如果继承自Thread类,不适合多个线程共享资源,而实现了Runnable接口可以方便的实现资源共享。

    public class ThreadDemo2 extends Thread{
        private String name;
        private int ticket=15;
        public void run(){
            for(int i=0;i<=15;i++){
                if(ticket>0){
                    System.out.println(name+"卖票:ticket="+ticket--);
                }
            }
        }
        public ThreadDemo2(String name){
            this.name=name;
        }
        public static void main(String[] args){
            ThreadDemo2 demo1=new ThreadDemo2("线程A");
            ThreadDemo2 demo2=new ThreadDemo2("线程B");
            ThreadDemo2 demo3=new ThreadDemo2("线程C");
            new Thread(demo1).start();
            new Thread(demo2).start();
            new Thread(demo3).start();
        }
    }
    //结果证明线程A,B,C都各自卖出15张票


    public class RunnableDemo2 implements Runnable{
       private int ticket=10;
        
        public void run() {
            for(int i=1;i<=5;i++){
                if(ticket>0){
                    System.out.println("卖票:ticket="+ticket--);
                }
            }        
        }
        public static void main(String[] args) {
            RunnableDemo2 demo1=new RunnableDemo2();
            new Thread(demo1).start();
            new Thread(demo1).start();
            new Thread(demo1).start();
        }
    }
    //结果如下:卖票:ticket=10
    卖票:ticket=9
    卖票:ticket=8
    卖票:ticket=7
    卖票:ticket=6
    卖票:ticket=5
    卖票:ticket=4
    卖票:ticket=3
    卖票:ticket=2
    卖票:ticket=1

    实现Runnable接口与继承自Thread类在实现多线程中相比具备以下优势

    (1) 适合多个具有相同程序代码的线程处理同一资源

    (2)避免java单继承特征带来的局限

    (3)代码能够被多个线程共享且数据独立存在,从而增强了程序的健壮性。

    4、线程同步

    同步是指同一时间段内只能运行一个线程,其他线程需要等待此线程完成后才可继续执行。同步可以解决线程中资源共享的安全问题,主要有同步代码块和同步方法两种方式完成。

    1)同步代码块格式

    synchronized(同步对象){

    需要同步的代码块

    }

    public class SynchronizedDemo implements Runnable{
        private int ticket=5;
        public void run() {
            for(int i=1;i<=5;i++){
                synchronized (this) {
                    if(ticket>0){
                        try{
                            Thread.sleep(1000);
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                        System.out.println("卖票:ticket="+ticket--);
                    }
                    
                }
            }        
        }
        public static void main(String[] args) {
            SynchronizedDemo demo1=new SynchronizedDemo();
            new Thread(demo1).start();
            new Thread(demo1).start();
            new Thread(demo1).start();
        }
    }

    结果如下:

    卖票:ticket=5
    卖票:ticket=4
    卖票:ticket=3
    卖票:ticket=2
    卖票:ticket=1

    如果没有加入线程同步方法,则卖票会出现负数

    另外有同步方法

    格式如下:

    synchronized 方法返回类型方法名称(参数列表){

    }

    5、线程的生命周期/

    1)创建状态

    2)就绪状态

    3)运行状态

    4)阻塞状态

    5)终止状态

    6、加入js的理解

    先看一段代码

    var x = document.getElementsByName(data);
    var i;
    for (i = 0; i < x.length; i++) {
       var value=x[i].id;
       $.getJSON(ctx + '/sys/dict/description', {
          value: value
       }, function (data) {
       var str = '&nbsp;<img src="/static/images/toolbox/description.png" title="'+data.value+'"/>';
       $('.tooltip-description [desc='+value+']').append(str);
     });

    本段代码的意图是根据元素名取得页面上所有元素,然后逐个发送请求到后台,将根据该得到的数据在页面上进行展示,代码中,for循环应是一个原子操作,但$.getJSON()是异步请求数据,第一个请求还没结束,第二个就已经开始,导致数据混乱,因此应对for循环进行修改,使其变为线程安全,具体做法是在for循环之前加一段代码:

    var x = document.getElementsByName(data);
    var i;
    $.ajaxSettings.async = false;
       for (i = 0; i < x.length; i++) {
          var value=x[i].id;
          $.getJSON(ctx + '/sys/dict/description', {
             value: value
          }, function (data) {
          var str = '&nbsp;<img src="/static/images/toolbox/description.png" title="'+data.value+'"/>';
          $('.tooltip-description [desc='+value+']').append(str);
           });
    其实我是叫smith的。
  • 相关阅读:
    Elasticsearch--ES-Head--docker版安装
    springboot配置rabbitmq
    springboot开启多线程配置
    Hyper-v安装centos后的网络配置
    阿里云服务器centos7,docker部署mysql+Redis+vue+springboot+Nginx+fastdfs,亲测可用
    安装docker-compose
    装饰器
    数据类型操作中的坑 循环删除
    python数据类型:字典dict常用操作
    函数def
  • 原文地址:https://www.cnblogs.com/smithXiao/p/9455760.html
Copyright © 2011-2022 走看看