zoukankan      html  css  js  c++  java
  • Java多线程小结

    简述

    Java是支持多线程编程的语言,线程相比于进程更加轻量级,线程共享相同的内存空间,但是拥有独立的栈。减少了进程建立、销毁的资源消耗。jdk1.5后对java的多线程编程提供了更完善的支持,使得java的多线程编程更加方便简洁。本文旨在通过对Java多线程知识的梳理,整理出一个大纲,使得读者对多线程的编程有更加完善的认识。

    线程生命周期的管理

    • 线程的创建
      java中线程的创建主要有两种方式:
    1. 继承Thread类(Thread中方法主要用于针对线程本身的处理);
    2. 实现Runnable接口;
    • 线程的通讯
      线程之间的通讯实际上是线程之间传递参数的问题。
    1. 往线程中传递参数: 通过新建线程的构造函数;
    2. 线程执行中,往外界传递参数:
      • 通过方法的返回值,但可能线程未执行完成,所以返回NULL。所以,用轮询的方式,获取方法返回值。
        缺点是浪费CPU周期。
      • 通过注册回调方法,在构造线程的时候传入回调类,然后,在线程执行过程中调用回调方法。
      • JDK1.5,提供了Future、Callable和Executor,Executor子类ExecutorService创建线程,实现Callable接口作为回调方法(实现call()方法),返回一个Future类。
    • 线程同步
      当多线程共享资源时,必须考虑同步问题。可以用synchronized关键字标注关键对象或方法。但是,同步不仅影响性能,同步的越多越容易造成死锁问题。(死锁:两个线程想要独占某种资源,但是,两者同时占用这种资源的子集的情况)

      同步的替代方法:

    1. 尽可能使用局部变量而不是字段,基本类型传参是值传递,是线程安全的(String也是安全的,一旦创建不能更改);
    2. 构造函数一般不需要考虑线程安全问题;
    3. 将非线程安全的类作为线程安全类的一个私有字段;

    注:多线程中使用System.out输出,也属于共享资源。

    • 线程的调度
      JVM的线程调度器,抢占式的(preemptive)和协作式的(cooperative)。由于一个线程长时间占用CPU,会造成其他线程的饥饿状况。可以通过设置线程的优先级来改变这种情况,但是,在相同优先级的线程中,需要使用如下6种类方法,手动控制:
    1. 对I/O阻塞;
    2. 放弃,调用Thread.yield(),提供给相同优先级的线程CPU的使用机会;
    3. 休眠,sleep(),提供给相同优先级及以下优先级CPU的使用机会;
    4. 连接线程,join(),等待某个指定线程执行结束,或者执行一段时间;
    5. 等待某个对象,wait(),放弃对一个对象的锁定并暂停(之前的方法并不会放弃资源);
    6. 结束,方法返回return;

    线程池

    dk1.5对线程池提供了很好的支持。线程池的建立主要是为了减少内存资源的损耗,减少线程新建和删除的损耗,通过将任务(特定的线程)放置到队列中,然后,使用不同的策略,利用线程池中的线程处理队列中的任务。
    ExecutorService调用一个基础API创建线程池,通过不同队列实现不同特性的线程池。队列是独立于线程池的一部分,用于放置线程池中未及时处理的任务。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 线程池包装
     */
    public class BearThreadPool {
    
        private ExecutorService pool;
    
        public void createCachedThreadPool(){
            pool = Executors.newCachedThreadPool();
        }
    
    
    
        public void addTask(Runnable task){
            pool.submit(task);
        }
    
        public void termination(){
            pool.shutdown();
        }
    }
    
    
    /**
     * 线程
     */
    public class Task implements Runnable {
    
        private String taskId;
        private TaskCallBack callback;
        public Task(String taskId, TaskCallBack callback){
            this.taskId = taskId;
            this.callback = callback;
        }
    
        public void run() {
            synchronized (System.out){
                System.out.println(taskId);
                callback.before();
                callback.middle();
                callback.after();
                System.out.println("==========");
            }
    
        }
    }
    
    
    /**
     * 回调函数接口
     */
    public interface TaskCallBack {
    
        void before();
    
        void middle();
    
        void after();
    
    }
    
    
  • 相关阅读:
    lazyload【思路】
    图片旋转
    模拟滚动条【大体功能实现】
    Firefox window.close()的使用注意事项
    修改KindEditor的CSS文件
    ownerDocument property
    网易新闻图片展示效果
    关于td不支持position问题
    strcat strncat
    Tcl_FindExecutable
  • 原文地址:https://www.cnblogs.com/zhengruin/p/5939091.html
Copyright © 2011-2022 走看看