zoukankan      html  css  js  c++  java
  • java多线程

    当有多个客户端请求连接服务端时,这时服务端应采取多线程进行处理,每接收到一个请求,就创建一个线程处理此请求。
    ServerSocket serverSocket=new ServerSocket(8888);
    Socket socket=null;
    while(true){
          socket=serverSocket.accept();
          ServerThread serverThread=new ServerThread(socket);
          serverThread.start();
    }
     
    -----------------------------------------------------------------------------------------
    ServerThread extends Thread{
             Socket socket;
             public ServerThread( Socket socket){
                    this.socket=socket;
    }
            public void run(){
                   socket.getInputStream();
                   ......
    }
    }
     
    --------------------------------------------------------------------------------------------
    还有一种创建多线程的方法:如果类继承了某个类,这时就只能通过实现Runnable接口来创建了。
    A implements Runnable{
            public void run(){
                     .....
    }
    }
     
    为了启动A,需要首先实例化一个Thread,并传入A实例:
    Thread thread=new Thread(a);
    thread.start();
    ----------------------------------------------------------------------------------------------------------------------------
    查看Thread类的源码,可以看到,该类实现了Runnable接口,成员变量有一个为Runnable target,构造方法Thread(Runnable target)会调用Thread类的init()方法,在init()方法体中赋予值:this.target=target。Thread
    类有一个run()方法,该方法判断是否有target,如果有就调用target.run;如果没有,就执行自身的run方法,但是
    自身的run()方法什么内容都没有,所以就需要覆写run()方法。
    因此,创建一个线程的两种实现方式分别为:
    Thread thread=new Thread(){
        @Override
        void run(){
            //执行代码
    }
    };
    thread.start();
     
    Thread thread1=new Thread(new Runnable(){
        @Override
        void run(){
            //执行代码
    }
    });
    thread1.start();
    ------------------------------------------------------------------------------------------------------------------------
    多线程真的能够提高程序效率吗?如果对于单核CPU而言,它要同时执行好几个线程,那么线程之间的切换
    需要消耗部分时间,而且线程的同步使用锁机制,频繁的加锁和释放锁也很大的性能开销。
    网络上采用多线程下载视频 速度非常快,这是为什么呢?如果只有一个线程从服务器下载资源,服务器分配给该线程
    的带宽为20,但是假设有10个线程同时从服务器下载资源,服务器分配的带宽就为200了。
     
    —————————————————————————————————————————
    定时器Timer:该类可以实现一个定时器的功能,即多少秒执行一次任务。
    new Timer().schedule(new TimerTask(){
        @Override
        public void run(){
                //该线程执行某项任务
    }
    },3000);
    这个TimerTask就是一个线程,实现了Runnable接口。
    ---------------------------------------------------------------------------------------------------------------------------------
    如果多个线程在同一时间对同一个对象进行操作,就会产生线程安全问题。a线程中的方法还没有执行完,
    又去执行b线程中的方法了(cpu在线程之间进行不规律的切换),结果成员变量的值就会不一致了。
    解决方法:利用synchronized给对象加锁
    每个对象的对象头都有一把锁,只有当线程获取到该对象的锁之后,才能执行对象中的方法。
    有三种加锁机制(synchronized只能对方法加锁):
    public synchronized void foo(){
    }
     
    public synchronized static void foo1(){
    }
     
    public void foo3(){
        synchronizde(this){
    }
    }
     
    public synchronized void foo4(){
    }
     
    public void foo5(){
    }
    a线程要执行foo()方法,必须获得对象的锁,获得到了就进来执行,此时如果b线程访问foo()或者foo4(),都得先获取对象的锁,但是此时对象的锁还没有释放,所以就不能访问到。但是如果此时b线程访问foo5(),由于访问foo5()时并不需要先获得锁,所以b线程可以随时访问到。
     
    如果对类方法foo1()加锁,那么必须首先获得类对象的锁才能访问,此时如果b线程访问foo1(),依然能够访问到,因为它们加的锁不一样,一个是对类对象加的锁,一个是对类的实例对象加的锁。
    ---------------------------------------------------------------------------------------------------------------------------------
    线程同步:a线程在运行的时候,b线程需要等待(wait),待到a线程运行到一定时候,会改变信号量,停止当前线程的执行,并唤醒b线程(notify);b线程唤醒之后,会执行相关代码(此时a线程处于wait()状态),b执行一段时间后,又改变信号量,并唤醒a线程。
    java.lang.Object类有wait()方法和notify()方法,其他类都是Object的子类,因此任何一个类都有wait()方法和notify()方法。
    信号量为boolean类型,在if或者while(可以预防假唤醒)语句中判断是否能够执行,但是在执行之前必须被唤醒。
    wait()和notify()方法必须用到同步代码块中,即方法中必须有synchronized同步锁。当执行this.notity()方法时,对象将锁抛出,其他线程可以竞争锁。
    -------------------------------------------------------------------------------------------------------------------------------------
    线程范围内的共享变量:A、B两个模块在a线程中共享同一变量,在b线程中共享另一(同一)变量。变量在线程内共享,但在线程间相互独立。
    ThreadLocal类用于解决线程范围内的共享变量问题。该类位于java.lang.ThreadLocal中,ThreadLocal类相当于一个Map中的一个Entry(数据结构为<Thread,data>,ThreadLocal类的T get()方法可以获得当前线程的共享变量,set(T value)可以设置当前线程的共享变量值),不同的线程享用不同的data,但是该data在同一个线程内共享。
    应用场景:在数据库的事务中,线程首先开启事务(getConnection.startTranction),然后执行操作,最后提交事务(getConnection.commit)。如果张三给李四转账,将使用同一个数据库连接connetion。假设在这个时候王五给赵六转账,也使用同一个connection,那么当王五connetion.commit的时候张三给李四转账的事务也跟着被提交了。所以这两个事务需要使用不同的数据库连接对象connection.
    -----------------------------------------------------------------------------------------------------------------------------------------
    Tomcat服务器中有一个连接池,客户端每发送一个Http请求,tomcat就调用一个线程处理该请求,该线程中的数据是线程范围内的共享数据,其他线程(连接请求)不能访问。连接池中存放的即是一个个ThreadLocal对象,每个对象包含了当前线程和data数据。如果有成千上万的请求访问该Tomcat服务器,就会创建出成千上万的ThreadLocal进行处理,那么ThreadLocal就必须要有 remove  ()方法删除线程中的数据,释放掉内存,释放完之后线程又回到了线程池中,等待下一个连接。
    数据库的单例模式:每当一个客户端连接一个服务器端的时候,就会创建一个connection连接对象与数据库进行交互。如果有connection对象,就不创建,否则创建一个connection对象,当下次同一个客户端再次连接的时候,就不需要再次创建connection对象了。
  • 相关阅读:
    本地MD5 SHA1 函数 的JS实现
    让用户减少学习成本——后台系统交互心得(二)(原创理论)
    样式库构建规范(转)
    基础css base.css(转)
    更贴近业务及用户——交互设计工作方式转变感言(原创理论)
    三栏布局,中间栏自适应
    你必须知道的【闭包】陷阱和案例-非常好
    css3 基础内容
    VB.Net实现登陆Ftp的方法
    .NET發送郵件功能開發
  • 原文地址:https://www.cnblogs.com/james111/p/6607389.html
Copyright © 2011-2022 走看看