日期: 2021 年 9 月 22 日

2020年全国科技经费投入统计公报

2020年全国科技经费投入统计公报[1] 国家统计局 科学技术部 财政部2021年9月22日   2020年,我国研究与试验发展(R&D)经费投入继续保持较快增长,投入强度持续提升,但受新冠肺炎疫情等因素影响,投入增速有所回落,国家财政科技支出比上年下降。   一、研究与试验发展(R&D)经费情况   2020年,全国共投入研究与试验发展(R&D)经费24393.1亿元,比上年增加2249.5亿元,增长10.2%,增速比上年回落2.3个百分点;研究与试验发展(R&D)经费投入强度(与国内生产总值[2]之比)为2.40%,比上年提高0.16个百分点[3]。按研究与试验发展(R&D)人员全时工作量计算的人均经费为46.6万元,比上年增加0.5万元。   分活动类型看,全国基础研究经费1467.0亿元,比上年增长9.8%;应用研究经费2757.2亿元,增长10.4%;试验发展经费20168.9亿元,增长10.2%。基础研究、应用研究和试验发展经费所占比重分别为6.0%、11.3%和82.7%。   分活动主体看,各类企业研究与试验发展(R&D)经费支出18673.8亿元,比上年增长10.4%;政府属研究机构经费支出3408.8亿元,增长10.6%;高等学校经费支出1882.5亿元,增长4.8%。企业、政府属研究机构、高等学校经费支出所占比重分别为76.6%、14.0%和7.7%。   分产业部门看,高技术制造业研究与试验发展(R&D)经费4649.1亿元,投入强度(与营业收入之比)为2.67%,比上年提高0.26个百分点;装备制造业研究与试验发展(R&D)经费9130.3亿元,投入强度为2.22%,比上年提高0.15个百分点。在规模以上工业企业中,研究与试验发展(R&D)经费投入超过500亿元的行业大类有10个,这10个行业的经费占全部规模以上工业企业研究与试验发展(R&D)经费的比重为73.6%(详见附表1)。   分地区看,研究与试验发展(R&D)经费投入超过千亿元的省(市)有8个,分别为广东(3479.9亿元)、江苏(3005.9亿元)、北京(2326.6亿元)、浙江(1859.9亿元)、山东(1681.9亿元)、上海(1615.7亿元)、四川(1055.3亿元)和湖北(1005.3亿元)。研究与试验发展(R&D)经费投入强度(与地区生产总值[4]之比)超过全国平均水平的省(市)有7个,分别为北京、上海、天津、广东、江苏、浙江和陕西(详见附表2)。   二、财政科学技术支出情况   2020年,国家财政科学技术支出10095.0亿元,比上年减少622.4亿元,下降5.8%。其中,中央财政科学技术支出3758.2亿元,下降9.9%,占财政科学技术支出的比重为37.2%;地方财政科学技术支出6336.8亿元,下降3.2%,占比为62.8%。 2020年财政科学技术支出情况  财政科学技术支出(亿元)比上年增长(%)占财政科学技术支出的比重(%)
合 计10095.0-5.8—-
其中:科学技术支出9018.3-4.889.3
   其他功能支出中用于科学技术的支出1076.7-13.610.7
其中:中央3758.2-9.937.2
   地方6336.8-3.262.8
注:本表中财政科学技术支出的统计范围为公共财政支出安排的科技项目。 注:[1]本公报各项统计数据均未包括香港特别行政区、澳门特别行政区和台湾省。部分数据因四舍五入的原因,存在总计与分项合计不等的情况。[2]2020年国内生产总值为初步核算数据。[3]根据2019年国内生产总值(GDP)*终核实数据,2019年研究与试验发展(R&D)经费投入强度已修订为2.24%。[4]2020年地区生产总值为初步核算数据。 附表1 2020年分行业规模以上工业企业研究与试验发展(R&D)经费情况 行业R&D经费(亿元)R&D经费投入强度(%)
合 计15271.3 1.41 采矿业294.8 0.73 煤炭开采和洗选业120.1 0.58 石油和天然气开采业80.1 1.20 黑色金属矿采选业18.3 0.44 有色金属矿采选业22.6 0.82 非金属矿采选业20.3 0.55 开采专业及辅助性活动33.4 1.58 制造业14783.8 1.54 农副食品加工业276.6 0.57 食品制造业157.3 0.81 酒、饮料和精制茶制造业89.7 0.61 烟草制品业28.0 0.25 纺织业231.4 0.99 纺织服装、服饰业105.8 0.76 皮革、毛皮、羽毛及其制品和制鞋业90.3 0.89 木材加工和木、竹、藤、棕、草制品业67.3 0.78 家具制造业90.7 1.28 造纸和纸制品业136.6 1.04 印刷和记录媒介复制业93.6 1.41 文教、工美、体育和娱乐用品制造业101.5 0.83 石油、煤炭及其他燃料加工业189.6 0.45 化学原料和化学制品制造业797.2 1.25 医药制造业784.6 3.13 化学纤维制造业132.4 1.66 橡胶和塑料制品业444.8 1.74 非金属矿物制品业513.1 0.88 黑色金属冶炼和压延加工业799.3 1.09 有色金属冶炼和压延加工业418.8 0.77 金属制品业561.9 1.44 通用设备制造业977.9 2.38 专用设备制造业966.0 2.85 汽车制造业1363.4 1.67 铁路、船舶、航空航天和其他运输设备制造业485.2 3.13 电气机械和器材制造业1567.1 2.26 计算机、通信和其他电子设备制造业2915.2 2.35 仪器仪表制造业293.7 3.59 其他制造业48.1 1.98 废弃资源综合利用业38.4 0.65 金属制品、机械和设备修理业18.7 1.28 电力、热力、燃气及水生产和供应业192.7 0.24 电力、热力生产和供应业151.8 0.22 燃气生产和供应业23.6 0.25 水的生产和供应业17.2 0.48 附表2 2020年各地区研究与试验发展(R&D)经费情况 地 区R&D经费(亿元)R&D经费投入强度(%)
全 国24393.12.40
北 京2326.66.44
天 津485.03.44
河 北634.41.75
山 西211.11.20
内蒙古161.10.93
辽 宁549.02.19
吉 林159.51.30
黑龙江173.21.26
上 海1615.74.17
江 苏3005.92.93
浙 江1859.92.88
安 徽883.22.28
福 建842.41.92
江 西430.71.68
山 东1681.92.30
河 南901.31.64
湖 北1005.32.31
湖 南898.72.15
广 东3479.93.14
广 西173.20.78
海 南36.60.66
重 庆526.82.11
四 川1055.32.17
贵 州161.70.91
云 南246.01.00
西 藏4.40.23
陕 西632.32.42
甘 肃109.61.22
青 海21.30.71
宁 夏59.61.52
新 疆61.60.45   附注:   1.主要指标解释   研究与试验发展(R&D)经费 指报告期为实施研究与试验发展(R&D)活动而实际发生的全部经费支出。研究与试验发展(R&D)指为增加知识存量(也包括有关人类、文化和社会的知识)以及设计已有知识的新应用而进行的创造性、系统性工作,包括基础研究、应用研究和试验发展三种类型。国际上通常采用研究与试验发展(R&D)活动的规模和强度指标反映一国的科技实力和核心竞争力。   基础研究 指一种不预设任何特定应用或使用目的的实验性或理论性工作,其主要目的是为获得(已发生)现象和可观察事实的基本原理、规律和新知识。   应用研究 指为获取新知识,达到某一特定的实际目的或目标而开展的初始性研究。应用研究是为了确定基础研究成果的可能用途,或确定实现特定和预定目标的新方法。   试验发展 指利用从科学研究、实际经验中获取的知识和研究过程中产生的其他知识,开发新的产品、工艺或改进现有产品、工艺而进行的系统性研究。   2.统计范围   研究与试验发展(R&D)经费的统计范围为全社会有R&D活动的企事业单位,具体包括政府属研究机构、高等学校以及R&D活动相对密集行业(包括农、林、牧、渔业,采矿业,制造业,电力、热力、燃气及水生产和供应业,建筑业,交通运输、仓储和邮政业,信息传输、软件和信息技术服务业,金融业,租赁和商务服务业,科学研究和技术服务业,水利、环境和公共设施管理业,卫生和社会工作,文化、体育和娱乐业等)的企事业单位。   3.调查方法   研究与试验发展(R&D)经费的调查方法是:规模以上工业企业,特、一级建筑业企业,规模以上服务业(包括交通运输、仓储和邮政业,信息传输、软件和信息技术服务业,租赁和商务服务业,科学研究和技术服务业,水利、环境和公共设施管理业,卫生和社会工作,文化、体育和娱乐业)企业,政府属研究机构,高等学校采用全面调查取得,规模以下工业企业和服务业企业采用抽样调查推算取得,其他行业的企事业单位采用重点调查以及使用第二次全国R&D资源清查资料推算等方法取得。

国家统计局社科文司统计师张启龙解读《2020年全国科技经费投入统计公报》

R&D经费投入较快增长 企业研发投入主体作用凸显 ——国家统计局社科文司统计师张启龙解读《2020年全国科技经费投入统计公报》   日前,国家统计局、科学技术部和财政部联合发布了《2020年全国科技经费投入统计公报》,国家统计局社科文司统计师张启龙对此进行了解读。   一、研究与试验发展(R&D)经费投入再创新高,投入强度继续提高   《公报》数据显示,2020年我国R&D经费投入总量突破2.4万亿,达到24393.1亿元,比上年增加2249.5亿元,增长10.2%,延续了“十三五”以来两位数以上增长态势,但受新冠肺炎疫情等因素影响,增速较上年回落2.3个百分点。由于R&D经费增速比现价GDP增速快7.2个百分点,R&D经费投入强度(与GDP之比)达到2.40%,比上年提高0.16个百分点,提升幅度创近11年来新高。   从国际比较看,我国R&D经费投入呈现稳中有进态势。一是总量稳定增长。2020年,我国R&D经费总量约为美国[1]54%,是日本的2.1倍,稳居世界第二;2016—2019年,我国R&D经费年均净增量超过2000亿元,约为G7国家[2]年均增量总和的60%,成为拉动全球R&D经费增长的主要力量。二是增速全球领跑。2016—2019年,我国R&D经费年均增长11.8%,增速远高于美国(7.3%)、日本(0.7%)等科技强国。三是强度追赶加快。在世界主要经济体中,我国R&D投入强度水平已从2016年的世界第16位提升到第12位,接近OECD国家的平均水平。   二、企业拉动作用增强,区域协调发展进一步巩固   (一)企业拉动作用进一步增强。2020年,企业R&D经费18673.8亿元,比上年增长10.4%;占全国R&D经费的比重达76.6%,对全国增长的贡献达77.9%,分别比上年提高0.2和9.4个百分点,拉动作用进一步增强。其中,规模以上工业企业R&D经费15271.3亿元,比上年增长9.3%;投入强度(与营业收入之比,下同)为1.41%,比上年提高0.09个百分点。重点领域R&D经费投入强度稳步提高,为关键核心技术攻关和产业基础能力提升创造条件。在规模以上工业中,高技术制造业R&D经费4649.1亿元,投入强度为2.67%,比上年提高0.26个百分点;装备制造业R&D经费9130.3亿元,投入强度为2.22%,比上年提高0.15个百分点。   (二)中西部地区研发投入增势良好。2020年,我国东、中、西部地区[3]R&D经费分别为16517.3 亿元、4662.9亿元和3212.9亿元,分别比上年增长9.2%、12.0%和12.4%,中西部地区增速连续4年超过东部地区,追赶态势明显。R&D经费超过千亿元的省份达到8个,比上年增加2个。从重点区域看,京津冀、长三角地区R&D经费分别为3446.0亿元和7364.7亿元,分别比上年增长5.6%和9.5%;长江经济带R&D经费达到11689.2亿元,比上年增长10.7%,增速快于全国平均水平。   三、基础研究经费保持增长,占比基本稳定   (一)基础研究经费增长放缓。2020年,我国基础研究经费为1467.0亿元,比上年增长9.8%,增速较上年回落12.7个百分点;占R&D经费比重为6.01%,连续两年保持在6%以上。   (二)高校院所增速回落。高等学校和政府属研究机构是我国基础研究活动两大执行主体,受疫情影响,复学复工较为延迟,对部分科研活动产生一定影响。2020年,高等学校、政府属研究机构基础研究经费分别为724.8亿元和573.9亿元,分别比上年增长0.4%和12.5%,增速较上年分别回落22.0和8.1个百分点,二者对全国基础研究经费增长贡献率由上年的89.6%减少到50.4%,是基础研究增速放缓的主要原因。   四、创新支持政策取得成效,财政科技支出受疫情影响有所下降   (一)政策支持效果显现。随着研发费用加计扣除政策进一步完善,2020年,规模以上企业享受研发费用加计扣除减免税金额为2421.9亿元,比上年增长29.4%。相关调查显示,企业对该政策认可度高达87.7%,比上年提高2.7个百分点。以“减税”替代“直补”支持创新政策取得良好成效,企业研发活动积*性持续提升,规模以上开展研发活动企业占比为28.4%,比上年提高2个百分点。相关部门明确将制造业企业研发加计扣除比例由75%提高到100%,有望带动企业进一步加大科技创新投入、提高技术能力和产业链供应链水平。   (二)财政科技支出有所下降。根据全国财政决算数据,2020年国家财政科学技术支出为10095.0亿元,比上年减少622.4亿元,下降5.8%。其中,中央财政科学技术支出3758.2亿元,下降9.9%,占财政科学技术支出的比重为37.2%;地方财政科学技术支出6336.8亿元,下降3.2%,占比为62.8%。中央和地方财政科技支出下降,主要受新冠肺炎疫情影响,当年部分财政支持科技项目出现了延迟或暂缓执行的情况。   2020年是*不平凡的一年,面对疫情冲击和复杂严峻的国内外环境,我国R&D经费保持了较快增长,为抗击疫情和全面建成小康社会提供了有力保障。未来,在继续扩大经费投入规模的同时,还需进一步优化经费投入结构,提高投入质效。一是优化政府资金投放,在保增长基础上,进一步向经济社会发展*迫切的重大需求集中、向重点领域关键行业倾斜,改进经费预算管理和拨付方式,发挥好“指挥棒”作用。二是发挥企业主体作用,鼓励企业进一步加大对原始创新和自主攻关的投入,通过组建创新联合体等方式强化产学研合作,提升“主力军”战力。三是健全全社会多元化投入机制,完善社会捐赠、风险投资、金融科技产品等资金来源渠道,大力发展新型研发机构,营造“多元化”生态。 注: 1.美国和日本R&D经费数据为2019年数据。 2.G7国家指美国、英国、德国、法国、日本、加拿大和意大利。 3.东部地区包括:北京、天津、河北、辽宁、上海、江苏、浙江、福建、山东、广东和海南;中部地区包括:山西、吉林、黑龙江、安徽、江西、河南、湖北和湖南;西部地区包括:内蒙古、广西、重庆、四川、贵州、云南、西藏、陕西、甘肃、青海、宁夏和新疆。

Android 多线程之IntentService 完全详解

Android 多线程之IntentService 完全详解

 

IntentService

一、IntentService概述

上一篇我们聊到了HandlerThread,本篇我们就来看看HandlerThread在IntentService中的应用,看本篇前建议先看看上篇的HandlerThread,有助于我们更好掌握IntentService。同样地,我们先来看看IntentService的特点:

  • 它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类
  • 它可以用于在后台执行耗时的异步任务,当任务完成后会自动停止
  • 它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务
  • 它内部通过HandlerThread和Handler实现异步操作
  • 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作

二、IntentService的常规使用套路

大概了解了IntentService的特点后,我们就来了解一下它的使用方式,先看个案例:
IntentService实现类如下:

package com.zejian.handlerlooper;

import android.app.IntentService;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.os.Message;

import com.zejian.handlerlooper.util.LogUtils;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by zejian
 * Time 16/9/3.
 * Description:
 */
public  class MyIntentService extends IntentService {
    public static final String DOWNLOAD_URL="download_url";
    public static final String INDEX_FLAG="index_flag";
    public static UpdateUI updateUI;


    public static void setUpdateUI(UpdateUI updateUIInterface){
        updateUI=updateUIInterface;
    }

    public MyIntentService(){
        super("MyIntentService");
    }

    /**
     * 实现异步任务的方法
     * @param intent Activity传递过来的Intent,数据封装在intent中
     */
    @Override
    protected void onHandleIntent(Intent intent) {

        //在子线程中进行网络请求
        Bitmap bitmap=downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
        Message msg1 = new Message();
        msg1.what = intent.getIntExtra(INDEX_FLAG,0);
        msg1.obj =bitmap;
        //通知主线程去更新UI
        if(updateUI!=null){
            updateUI.updateUI(msg1);
        }
        //mUIHandler.sendMessageDelayed(msg1,1000);

        LogUtils.e("onHandleIntent");
    }
    //----------------------重写一下方法仅为测试------------------------------------------
    @Override
    public void onCreate() {
        LogUtils.e("onCreate");
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        LogUtils.e("onStart");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LogUtils.e("onStartCommand");
        return super.onStartCommand(intent, flags, startId);

    }

    @Override
    public void onDestroy() {
        LogUtils.e("onDestroy");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        LogUtils.e("onBind");
        return super.onBind(intent);
    }


    public interface UpdateUI{
        void updateUI(Message message);
    }


    private Bitmap downloadUrlBitmap(String urlString) {
        HttpURLConnection urlConnection = null;
        BufferedInputStream in = null;
        Bitmap bitmap=null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
            bitmap= BitmapFactory.decodeStream(in);
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

}

 

通过代码可以看出,我们继承了IntentService,这里有两个方法是必须实现的,一个是构造方法,必须传递一个线程名称的字符串,另外一个就是进行异步处理的方法onHandleIntent(Intent intent) 方法,其参数intent可以附带从activity传递过来的数据。这里我们的案例主要利用onHandleIntent实现异步下载图片,然后通过回调监听的方法把下载完的bitmap放在message中回调给Activity(当然也可以使用广播完成),*后通过Handler去更新UI。下面再来看看Acitvity的代码:

activity_intent_service.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

 

IntentServiceActivity.java

package com.zejian.handlerlooper.util;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

import com.zejian.handlerlooper.MyIntentService;
import com.zejian.handlerlooper.R;

/**
 * Created by zejian
 * Time 16/9/3.
 * Description:
 */
public class IntentServiceActivity extends Activity implements MyIntentService.UpdateUI{
    /**
     * 图片地址集合
     */
    private String url[] = {
            "http://img.blog.csdn.net/20160903083245762",
            "http://img.blog.csdn.net/20160903083252184",
            "http://img.blog.csdn.net/20160903083257871",
            "http://img.blog.csdn.net/20160903083257871",
            "http://img.blog.csdn.net/20160903083311972",
            "http://img.blog.csdn.net/20160903083319668",
            "http://img.blog.csdn.net/20160903083326871"
    };

    private static ImageView imageView;
    private static final Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            imageView.setImageBitmap((Bitmap) msg.obj);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);
        imageView = (ImageView) findViewById(R.id.image);

        Intent intent = new Intent(this,MyIntentService.class);
        for (int i=0;i<7;i++) {//循环启动任务
            intent.putExtra(MyIntentService.DOWNLOAD_URL,url[i]);
            intent.putExtra(MyIntentService.INDEX_FLAG,i);
            startService(intent);
        }
        MyIntentService.setUpdateUI(this);
    }

    //必须通过Handler去更新,该方法为异步方法,不可更新UI
    @Override
    public void updateUI(Message message) {
        mUIHandler.sendMessageDelayed(message,message.what * 1000);
    }
}

 

代码比较简单,通过for循环多次去启动IntentService,然后去下载图片,注意即使我们多次启动IntentService,但IntentService的实例只有一个,这跟传统的Service是一样的,*终IntentService会去调用onHandleIntent执行异步任务。这里可能我们还会担心for循环去启动任务,而实例又只有一个,那么任务会不会被覆盖掉呢?其实是不会的,因为IntentService真正执行异步任务的是HandlerThread+Handler,每次启动都会把下载图片的任务添加到依附的消息队列中,*后由HandlerThread+Handler去执行。好~,我们运行一下代码:
%title插图%num
每间隔一秒去更新图片,接着我们看一组log:
%title插图%num
从Log可以看出onCreate只启动了一次,而onStartCommand和onStart多次启动,这就证实了之前所说的,启动多次,但IntentService的实例只有一个,这跟传统的Service是一样的,*后任务都执行完成后,IntentService自动销毁。以上便是IntentService德使用方式,怎么样,比较简单吧。接着我们就来分析一下IntentService的源码,其实也比较简单只有100多行代码。

三、IntentService源码解析

我们先来看看IntentService的onCreate方法:

@Override
public void onCreate() {
   // TODO: It would be nice to have an option to hold a partial wakelock
   // during processing, and to have a static startService(Context, Intent)
   // method that would launch the service & hand off a wakelock.

   super.onCreate();
   HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
   thread.start();

   mServiceLooper = thread.getLooper();
   mServiceHandler = new ServiceHandler(mServiceLooper);
}

 

当*启动IntentService时,它的onCreate方法将会被调用,其内部会去创建一个HandlerThread并启动它,接着创建一个ServiceHandler(继承Handler),传入HandlerThread的Looper对象,这样ServiceHandler就变成可以处理异步线程的执行类了(因为Looper对象与HandlerThread绑定,而HandlerThread又是一个异步线程,我们把HandlerThread持有的Looper对象传递给Handler后,ServiceHandler内部就持有异步线程的Looper,自然就可以执行异步任务了),那么IntentService是怎么启动异步任务的呢?其实IntentService启动后还会去调用onStartCommand方法,而onStartCommand方法又会去调用onStart方法,我们看看它们的源码:

@Override
public void onStart(Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

/**
 * You should not override this method for your IntentService. Instead,
 * override {@link #onHandleIntent}, which the system calls when the IntentService
 * receives a start request.
 * @see android.app.Service#onStartCommand
 */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

 

从源码我们可以看出,在onStart方法中,IntentService通过mServiceHandler的sendMessage方法发送了一个消息,这个消息将会发送到HandlerThread中进行处理(因为HandlerThread持有Looper对象,所以其实是Looper从消息队列中取出消息进行处理,然后调用mServiceHandler的handleMessage方法),我们看看ServiceHandler的源码:

private final class ServiceHandler extends Handler {
   public ServiceHandler(Looper looper) {
       super(looper);
   }

   @Override
   public void handleMessage(Message msg) {
       onHandleIntent((Intent)msg.obj);
       stopSelf(msg.arg1);
   }
}

 

这里其实也说明onHandleIntent确实是一个异步处理方法(ServiceHandler本身就是一个异步处理的handler类),在onHandleIntent方法执行结束后,IntentService会通过 stopSelf(int startId)方法来尝试停止服务。这里采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完后才终止服务。*后看看onHandleIntent方法的声明:

protected abstract void onHandleIntent(Intent intent);

到此我们就知道了IntentService的onHandleIntent方法是一个抽象方法,所以我们在创建IntentService时必须实现该方法,通过上面一系列的分析可知,onHandleIntent方法也是一个异步方法。这里要注意的是如果后台任务只有一个的话,onHandleIntent执行完,服务就会销毁,但如果后台任务有多个的话,onHandleIntent执行完*后一个任务时,服务才销毁。*后我们要知道每次执行一个后台任务就必须启动一次IntentService,而IntentService内部则是通过消息的方式发送给HandlerThread的,然后由Handler中的Looper来处理消息,而Looper是按顺序从消息队列中取任务的,也就是说IntentService的后台任务时顺序执行的,当有多个后台任务同时存在时,这些后台任务会按外部调用的顺序排队执行,我们前面的使用案例也很好说明了这点。*后贴一下到IntentService的全部源码,大家再次感受一下:

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.annotation.WorkerThread;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;

/**
 * IntentService is a base class for {@link Service}s that handle asynchronous
 * requests (expressed as {@link Intent}s) on demand.  Clients send requests
 * through {@link android.content.Context#startService(Intent)} calls; the
 * service is started as needed, handles each Intent in turn using a worker
 * thread, and stops itself when it runs out of work.
 *
 * <p>This "work queue processor" pattern is commonly used to offload tasks
 * from an application's main thread.  The IntentService class exists to
 * simplify this pattern and take care of the mechanics.  To use it, extend
 * IntentService and implement {@link #onHandleIntent(Intent)}.  IntentService
 * will receive the Intents, launch a worker thread, and stop the service as
 * appropriate.
 *
 * <p>All requests are handled on a single worker thread -- they may take as
 * long as necessary (and will not block the application's main loop), but
 * only one request will be processed at a time.
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For a detailed discussion about how to create services, read the
 * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
 * </div>
 *
 * @see android.os.AsyncTask
 */
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;

    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);
}

 

此IntentService的源码就分析完了,嗯,本篇完结。

Android IntentService完全解析 当Service遇到Handler

Android IntentService完全解析 当Service遇到Handler

一 概述

大家都清楚,在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能会被杀死,所以可以考虑将上传操作交给Service去做,如果担心Service被杀,还能通过设置startForeground(int, Notification)方法提升其优先级。

那么,在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService,我们看下注释。

IntentService is a base class for {@link Service}s that handle asynchronous
requests (expressed as {@link Intent}s) on demand. Clients send requests
through {@link android.content.Context#startService(Intent)} calls; the
service is started as needed, handles each Intent in turn using a worker
thread, and stops itself when it runs out of work.

意思说IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。

这么说,我们使用了IntentService*起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。

好了,那么接下来我们就来看一个完整的例子。

二 IntentService的使用

我们就来演示一个多个图片上传的案例,当然我们会模拟上传的耗时,毕竟我们的重心在IntentService的使用和源码解析上。

首先看下效果图

效果图

%title插图%num

每当我们点击一次按钮,会将一个任务交给后台的Service去处理,后台的Service每处理完成一个请求就会反馈给Activity,然后Activity去更新UI。当所有的任务完成的时候,后台的Service会退出,不会占据任何内存。

Service

package com.zhy.blogcodes.intentservice;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class UploadImgService extends IntentService
{
    private static final String ACTION_UPLOAD_IMG = "com.zhy.blogcodes.intentservice.action.UPLOAD_IMAGE";
    public static final String EXTRA_IMG_PATH = "com.zhy.blogcodes.intentservice.extra.IMG_PATH";

    public static void startUploadImg(Context context, String path)
    {
        Intent intent = new Intent(context, UploadImgService.class);
        intent.setAction(ACTION_UPLOAD_IMG);
        intent.putExtra(EXTRA_IMG_PATH, path);
        context.startService(intent);
    }


    public UploadImgService()
    {
        super("UploadImgService");
    }

    @Override
    protected void onHandleIntent(Intent intent)
    {
        if (intent != null)
        {
            final String action = intent.getAction();
            if (ACTION_UPLOAD_IMG.equals(action))
            {
                final String path = intent.getStringExtra(EXTRA_IMG_PATH);
                handleUploadImg(path);
            }
        }
    }

    private void handleUploadImg(String path)
    {
        try
        {
            //模拟上传耗时
            Thread.sleep(3000);

            Intent intent = new Intent(IntentServiceActivity.UPLOAD_RESULT);
            intent.putExtra(EXTRA_IMG_PATH, path);
            sendBroadcast(intent);

        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }


    }

    @Override
    public void onCreate()
    {
        super.onCreate();
        Log.e("TAG","onCreate");
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        Log.e("TAG","onDestroy");
    }
}

 

代码很短,主要就是继承IntentService,然后复写onHandleIntent方法,根据传入的intent来选择具体的操作。startUploadImg是我写的一个辅助方法,省的每次都去构建Intent,startService了。

Activity

package com.zhy.blogcodes.intentservice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.zhy.blogcodes.R;

public class IntentServiceActivity extends AppCompatActivity
{

    public static final String UPLOAD_RESULT = "com.zhy.blogcodes.intentservice.UPLOAD_RESULT";

    private LinearLayout mLyTaskContainer;

    private BroadcastReceiver uploadImgReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            if (intent.getAction() == UPLOAD_RESULT)
            {
                String path = intent.getStringExtra(UploadImgService.EXTRA_IMG_PATH);

                handleResult(path);

            }

        }
    };

    private void handleResult(String path)
    {
        TextView tv = (TextView) mLyTaskContainer.findViewWithTag(path);
        tv.setText(path + " upload success ~~~ ");
    }


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);

        mLyTaskContainer = (LinearLayout) findViewById(R.id.id_ll_taskcontainer);

        registerReceiver();
    }

    private void registerReceiver()
    {
        IntentFilter filter = new IntentFilter();
        filter.addAction(UPLOAD_RESULT);
        registerReceiver(uploadImgReceiver, filter);
    }

    int i = 0;

    public void addTask(View view)
    {
        //模拟路径
        String path = "/sdcard/imgs/" + (++i) + ".png";
        UploadImgService.startUploadImg(this, path);

        TextView tv = new TextView(this);
        mLyTaskContainer.addView(tv);
        tv.setText(path + " is uploading ...");
        tv.setTag(path);
    }


    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        unregisterReceiver(uploadImgReceiver);
    }
}

 

Activity中,每当我点击一次按钮调用addTask,就回模拟创建一个任务,然后交给IntentService去处理。

注意,当Service的每个任务完成的时候,会发送一个广播,我们在Activity的onCreate和onDestroy里面分别注册和解注册了广播;当收到广播则更新指定的UI。

布局文件

<LinearLayout android:id="@+id/id_ll_taskcontainer"
              xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
             >


    <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="addTask" android:text="add Task"/>
</LinearLayout>
  • 1

ok,这样我们就完成了我们的效果图的需求;通过上例,大家可以看到我们可以使用IntentService非常方便的处理后台任务,屏蔽了诸多细节;而Service与Activity通信呢,我们选择了广播的方式(当然这里也可以使用LocalBroadcastManager)。

学会了使用之后,我们再一鼓作气的看看其内部的实现。

三 IntentService源码解析

直接看IntentService源码

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;


public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }


    public IntentService(String name) {
        super();
        mName = name;
    }


    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
                super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    protected abstract void onHandleIntent(Intent intent);
}
  • 26

可以看到它在onCreate里面初始化了一个HandlerThread,关于HandlerThread的使用和源码
分析参考:Android HandlerThread 完全解析,看到这估计已经能猜到它的逻辑了:

就是每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);就可以了。

那么我们具体看一下源码,果然是这样,onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。*后handleMessage中回调onHandleIntent(intent)。

注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(*后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是*近发出的那一个(getLastStartId == startId),则会销毁我们的Service.

如果传入的是-1则直接销毁。

那么,当任务完成销毁Service回调onDestory,可以看到在onDestroy中释放了我们的Looper:mServiceLooper.quit()。

ok~ 如果你的需求可以使用IntentService来做,可以尽可能的使用,设计的还是相当赞的。当然了,如果你需要考虑并发等等需求,那么可能需要自己去扩展创建线程池等。

Java多线程中join方法的理解

Java多线程中join方法的理解

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join();      //使调用线程 t 在此之前执行完毕。
t.join(1000);  //等待 t 线程,等待时间是1000毫秒

 

先上一段JDK中代码:

  1. /** 
  2.      *  Waits at most <code>millis</code> milliseconds for this thread to   
  3.      * die. A timeout of <code>0</code> means to wait forever.   
  4.      */  
  5.     //此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。  
  6.     public final synchronized void join(long millis)    throws InterruptedException {  
  7.         long base = System.currentTimeMillis();  
  8.         long now = 0;  
  9.         if (millis < 0) {  
  10.             throw new IllegalArgumentException(“timeout value is negative”);  
  11.         }
  12.         if (millis == 0) {  
  13.             while (isAlive()) {  
  14.                 wait(0);  
  15.             }
  16.         } else {  
  17.             while (isAlive()) {  
  18.                 long delay = millis – now;  
  19.                 if (delay <= 0) {  
  20.                     break;  
  21.                 }
  22.                 wait(delay);
  23.                 now = System.currentTimeMillis() – base;
  24.             }
  25.         }
  26.     }

从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行

 

Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁

 

Example1:

  1. public class JoinTest implements Runnable{  
  2.     public static int a = 0;  
  3.     public void run() {  
  4.         for (int k = 0; k < 5; k++) {  
  5.             a = a + 1;  
  6.         }
  7.     }
  8.     public static void main(String[] args) throws Exception {  
  9.         Runnable r = new JoinTest();  
  10.         Thread t = new Thread(r);  
  11.         t.start();
  12.         System.out.println(a);
  13.     }
  14. }

请 问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。

  1. public static void main(String[] args) throws Exception {  
  2.         Runnable r = new JoinTest();  
  3.         Thread t = new Thread(r);  
  4.         t.start();
  5.         t.join(); //加入join()  
  6.         System.out.println(a);
  7.     }

这个时候,程序输入结果始终为5。

为 了证明如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。

  1. public static void main(String[] args) throws Exception {  
  2.         Runnable r = new JoinTest();  
  3.         Thread t = new Thread(r);  
  4.         t.start();
  5.         //t.join(); //加入join()  
  6.             /* 
  7.              注意循环体内一定要有实际执行语句,否则编译器或JVM可能优化掉你的这段代码,视这段代 
  8.              码为无效。             
  9.             */  
  10.             for (int i=0; i<300; i++) {                
  11.                 System.out.print(i);
  12.             }
  13.             System.out.println();
  14.         System.out.println(a);
  15.     }

经自己测试,*后a一直是5.

本例参考:http://agio.iteye.com/blog/210600

 

Example2:join(n)

  1. class RunnableImpl implements Runnable {  
  2.     public void run() {  
  3.         try {  
  4.             System.out.println(“Begin sleep”);  
  5.             Thread.sleep(1000);  
  6.            System.out.println(“End sleep”);  
  7.         } catch (InterruptedException e) {  
  8.             e.printStackTrace();
  9.         }
  10.     }
  11. }
  1. public class JoinTest{  
  2.     public static void main(String[] args) {  
  3.         Thread t = new Thread(new RunnableImpl());  
  4.         t.start();
  5.         try {  
  6.             t.join(1000);  
  7.             System.out.println(“joinFinish”);  
  8.         } catch (InterruptedException e) {  
  9.             e.printStackTrace();
  10.         }
  11.     }
  12. }

结果是:
Begin sleep
End sleep
joinFinish

明白了吧,当main线程调用t.join时,main线程等待t线程,等待时间是1000,如果t线程Sleep 2000呢

  1. class RunnableImpl implements Runnable {  
  2.     public void run() {  
  3.         try {  
  4.             System.out.println(“Begin sleep”);  
  5.             Thread.sleep(2000); //原来为1000  
  6.            System.out.println(“End sleep”);  
  7.         } catch (InterruptedException e) {  
  8.             e.printStackTrace();
  9.         }
  10.     }
  11. }

结果是:
Begin sleep
joinFinish
End sleep
也就是说main线程只等1000毫秒,不管T什么时候结束.

参考:http://blog.csdn.net/FG2006/archive/2011/05/04/6393768.aspx

 

Example3:

  1. class CustomThread1 extends Thread {    
  2.     public void run() {    
  3.         String threadName = Thread.currentThread().getName();
  4.         System.out.println(threadName + ” start.”);    
  5.         try {    
  6.             for (int i = 0; i < 5; i++) {    
  7.                 System.out.println(threadName + ” loop at ” + i);    
  8.                 Thread.sleep(1000);    
  9.             }
  10.             System.out.println(threadName + ” end.”);    
  11.         } catch (Exception e) {    
  12.             System.out.println(“Exception from ” + threadName + “.run”);    
  13.         }
  14.     }
  15. }
  16. class CustomThread extends Thread {    
  17.     CustomThread1 t1;
  18.     public CustomThread(CustomThread1 t1) {            
  19.         this.t1 = t1;    
  20.     }
  21.     public void run() {    
  22.         String threadName = Thread.currentThread().getName();
  23.         System.out.println(threadName + ” start.”);    
  24.         try {    
  25.             t1.join();
  26.             System.out.println(threadName + ” end.”);    
  27.         } catch (Exception e) {    
  28.             System.out.println(“Exception from ” + threadName + “.run”);    
  29.         }
  30.     }
  31. }
  32. public class JoinTestDemo {    
  33.     public static void main(String[] args) {    
  34.         String threadName = Thread.currentThread().getName();
  35.         System.out.println(threadName + ” start.”);    
  36.         CustomThread1 t1 = new CustomThread1();    
  37.         CustomThread t = new CustomThread(t1);    
  38.         try {    
  39.             t1.start();
  40.             Thread.sleep(2000);    
  41.             t.start();
  42.             t.join(); //在代碼2里,將此處注釋掉    
  43.         } catch (Exception e) {    
  44.             System.out.println(“Exception from main”);    
  45.         }
  46.         System.out.println(threadName + ” end!”);    
  47.     }
  48. }

结果:

main start.    //main方法所在的线程起动,但没有马上结束,因为调用t.join();,所以要等到t结束了,此线程才能向下执行。

[CustomThread1] Thread start.     //线程CustomThread1起动
[CustomThread1] Thread loop at 0  //线程CustomThread1执行
[CustomThread1] Thread loop at 1  //线程CustomThread1执行
[CustomThread] Thread start.      //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4  //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

main end!      //线程CustomThread结束,此线程在t.join();阻塞处起动,向下继续执行的结果。

 

将上例中的join注释掉:

  1. public class JoinTestDemo {    
  2.     public static void main(String[] args) {    
  3.         String threadName = Thread.currentThread().getName();
  4.         System.out.println(threadName + ” start.”);    
  5.         CustomThread1 t1 = new CustomThread1();    
  6.         CustomThread t = new CustomThread(t1);    
  7.         try {    
  8.             t1.start();
  9.             Thread.sleep(2000);    
  10.             t.start();
  11.            //t.join();  
  12.         } catch (Exception e) {    
  13.             System.out.println(“Exception from main”);    
  14.         }
  15.         System.out.println(threadName + ” end!”);    
  16.     }
  17. }

结果:

main start. // main方法所在的线程起动,但没有马上结束,这里并不是因为join方法,而是因为Thread.sleep(2000);

[CustomThread1] Thread start.      //线程CustomThread1起动
[CustomThread1] Thread loop at 0   //线程CustomThread1执行
[CustomThread1] Thread loop at 1   //线程CustomThread1执行
main end!   // Thread.sleep(2000);结束,虽然在线程CustomThread执行了t1.join();,但这并不会影响到其他线程(这里main方法所在的线程)。
[CustomThread] Thread start.       //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4   //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

本例参考:http://blog.csdn.net/bzwm/archive/2009/02/12/3881392.aspx

 

Example4 :

main 线程调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的 ,刚开的例子t.join(1000)不是说明了main线程等待1 秒,如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1毫秒了 。

  1. class RunnableImpl implements Runnable {  
  2.     public void run() {  
  3.         try {  
  4.             System.out.println(“Begin sleep”);  
  5.             Thread.sleep(2000);  
  6.             System.out.println(“End sleep”);  
  7.         } catch (InterruptedException e) {  
  8.             e.printStackTrace();
  9.         }
  10.     }
  11. }
  1. class ThreadTest extends Thread {  
  2.     Thread thread;
  3.     public ThreadTest(Thread thread) {  
  4.         this.thread = thread;  
  5.     }
  6.     @Override  
  7.     public void run() {  
  8.         synchronized (thread) {  
  9.             System.out.println(“getObjectLock”);  
  10.             try {  
  11.                 Thread.sleep(9000);  
  12.             } catch (InterruptedException ex) {  
  13.              ex.printStackTrace();
  14.             }
  15.             System.out.println(“ReleaseObjectLock”);  
  16.         }
  17.     }
  18. }
  1. public class JoinTest {  
  2.         public static void main(String[] args) {  
  3.             Thread t = new Thread(new RunnableImpl());  
  4.            new ThreadTest(t).start();  
  5.             t.start();
  6.             try {  
  7.                 t.join();
  8.                 System.out.println(“joinFinish”);  
  9.             } catch (InterruptedException e) {  
  10.                 e.printStackTrace();
  11.             }
  12.         }
  13. }

结果:
getObjectLock
Begin sleep
End sleep
ReleaseObjectLock
joinFinish

 

在main方法中 通过new  ThreadTest(t).start()实例化 ThreadTest 线程对象, 它 通过 synchronized  (thread) ,获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使main方法t.join(1000)等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000ms。

Java虚拟机工作原理详解 ( 二 )

Java虚拟机工作原理详解 ( 二 )

首先这里澄清两个概念:JVM实例和JVM执行引擎实例,JVM实例对应了一个独立运行的Java程序,而JVM执行引擎实例则对应了属于用户运行程序的线程;也就是JVM实例是进程级别,而执行引擎是线程级别的。

JVM是什么?—JVM的生命周期

JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有 publicstaticvoidmain(String[]args)函数的class都可以作为JVM实例运行的起点,既然如此,那么JVM如何知道 是运行classA的main而不是运行classB的main呢?这就需要显式的告诉JVM类名,也就是我们平时运行Java程序命令的由来,如 JavaclassAhelloworld,这里Java是告诉os运行SunJava2SDK的Java虚拟机,而classA则指出了运行JVM所需 要的类名。

JVM实例的运行:main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于 非守护线程,守护线程通常由JVM自己使用,Java程序也可以标明自己创建的线程是守护线程。JVM实例的消亡:当程序中的所有非守护线程都终止 时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。

JVM是什么?—JVM的体系结构

粗略分来,JVM的内部体系结构分为三部分,分别是:类装载器(ClassLoader)子系统,运行时数据区,和执行引擎。下面将先介绍类装载器,然后是执行引擎,*后是运行时数据区

1,类装载器,顾名思义,就是用来装载.class文件的。JVM的两种类装载器包括:启动类装载器和用户自定义类装载器,启动类装载器是JVM实现的一 部分,用户自定义类装载器则是Java程序的一部分,必须是ClassLoader类的子类。(下面所述情况是针对SunJDK1.2)

动类装载器:只在系统类(JavaAPI的类文件)的安装路径查找要装入的类

用户自定义类装载器:

系统类装载器:在JVM启动时创建,用来在CLASSPATH目录下查找要装入的类其他用户自定义类装载器:这里有必要先说一下ClassLoader类的几个方法,了解它们对于了解自定义类装载器如何装载.class文件至关重要。

  1. protectedfinalvoidresolveClass(Classc)

defineClass用来将二进制class文件(新类型)导入到方法区,也就是这里指的类是用户自定义的类(也就是负责装载类)

findSystemClass通过类型的全限定名,先通过系统类装载器或者启动类装载器来装载,并返回Class对象。

ResolveClass:让类装载器进行连接动作(包括验证,分配内存初始化,将类型中的符号引用解析为直接引用),这里涉及到Java命名空间的问 题,JVM保证被一个类装载器装载的类所引用的所有类都被这个类装载器装载,同一个类装载器装载的类之间可以相互访问,但是不同类装载器装载的类看不见对 方,从而实现了有效的屏蔽。

2,执行引擎:它或者在执行字节码,或者执行本地方法

要说执行引擎,就不得不的指令集,每一条指令包含一个单字节的操作码,后面跟0个或者多个操作数。

(一)指令集以栈为设计中心,而非以寄存器为中心这种指令集设计如何满足Java体系的要求:

平台无关性:以栈为中心使得在只有很少register的机器上实现Java更便利compiler一般采用stack向连接优化器传递编译的中间结果, 若指令集以stack为基础,则有利于运行时进行的优化工作与执行即时编译或者自适应优化的执行引擎结合,通俗的说就是使编译和运行用的数据结构统一,更 有利于优化的开展。

网络移动性:class文件的紧凑性。

安全性:指令集中*大部分操作码都指明了操作的类型。(在装载的时候使用数据流分析期进行一次性验证,而非在执行每条指令的时候进行验证,有利于提高执行速度)。

(二)执行技术

主要的执行技术有:解释,即时编译,自适应优化、芯片级直接执行其中解释属于*代JVM,即时编译JIT属于第二代JVM,自适应优化(目前Sun的HotspotJVM采用这种技术)则吸取*代JVM和第二代JVM的经验,采用两者结合的方式

自适应优化:开始对所有的代码都采取解释执行的方式,并监视代码执行情况,然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行仔细优化。若方法不再频繁使用,则取消编译过的代码,仍对其进行解释执行。

3,运行时数据区:主要包括:方法区,堆,Java栈,PC寄存器,本地方法栈

(1)方法区和堆由所有线程共享

堆:存放所有程序在运行时创建的对象

方法区:当JVM的类装载器加载.class文件,并进行解析,把解析的类型信息放入方法区。

(2)Java栈和PC寄存器由线程独享,在新线程创建时间里

(3)本地方法栈:存储本地方法调用的状态

上边总体介绍了运行时数据区的主要内容,下边进行详细介绍,要介绍数据区,就不得不说明JVM中的数据类型。

JVM中的数据类型:JVM中基本的数据单元是word,而word的长度由JVM具体的实现者来决定

数据类型包括基本类型和引用类型,

(1)基本类型包括:数值类型(包括除boolean外的所有的Java基本数据类型),boolean(在JVM中使用int来表示,0表示false,其他int值均表示true)和returnAddress(JVM的内部类型,用来实现finally子句)。

(2)引用类型包括:数组类型,类类型,接口类型

前边讲述了JVM中数据的表示,下面让我们输入到JVM的数据区

首先来看方法区:

上边已经提到,方法区主要用来存储JVM从class文件中提取的类型信息,那么类型信息是如何存储的呢?众所周知,Java使用的是大端序 (big?endian:即低字节的数据存储在高位内存上,如对于1234,12是高位数据,34为低位数据,则Java中的存储格式应该为12存在内存 的低地址,34存在内存的高地址,x86中的存储格式与之相反)来存储数据,这实际上是在class文件中数据的存储格式,但是当数据倒入到方法区中 时,JVM可以以任何方式来存储它。

类型信息:包括class的全限定名,class的直接父类,类类型还是接口类型,类的修饰符(public,等),所有直接父接口的列表,Class对 象提供了访问这些信息的窗口(可通过Class.forName(“”)或instance.getClass()获得),下面是Class的方法,相信 大家看了会恍然大悟,(原来如此J)

getName(),getSuperClass(),isInterface(),getInterfaces(),getClassLoader();

static变量作为类型信息的一部分保存

指向ClassLoader类的引用:在动态连接时装载该类中引用的其他类

指向Class类的引用:必然的,上边已述

该类型的常量池:包括直接常量(String,integer和floatpoint常量)以及对其他类型、字段和方法的符号引用(注意:这里的常量池并 不是普通意义上的存储常量的地方,这些符号引用可能是我们在编程中所接触到的变量),由于这些符号引用,使得常量池成为Java程序动态连接中至关重要的 部分

字段信息:普通意义上的类型中声明的字段

方法信息:类型中各个方法的信息

编译期常量:指用final声明或者用编译时已知的值初始化的类变量

class将所有的常量复制至其常量池或者其字节码流中。

方法表:一个数组,包括所有它的实例可能调用的实例方法的直接引用(包括从父类中继承来的)

除此之外,若某个类不是抽象和本地的,还要保存方法的字节码,操作数栈和该方法的栈帧,异常表。

举例:

  1. privateintspeed5LavalavanewLava}

 

 

运行命令JavaVolcano;

(1)JVM找到Volcano.class倒入,并提取相应的类型信息到方法区。通过执行方法区中的字节码,JVM执行main()方法,(执行时会一直保存指向Vocano类的常量池的指针)

(2)Main()中*条指令告诉JVM需为列在常量池*项的类分配内存(此处再次说明了常量池并非只存储常量信息),然后JVM找到常量池的* 项,发现是对Lava类的符号引用,则检查方法区,看Lava类是否装载,结果是还未装载,则查找“Lava.class”,将类型信息写入方法区,并将 方法区Lava类信息的指针来替换Volcano原常量池中的符号引用,即用直接引用来替换符号引用。

(3)JVM看到new关键字,准备为Lava分配内存,根据Volcano的常量池的*项找到Lava在方法区的位置,并分析需要多少对空间,确定后,在堆上分配空间,并将speed变量初始为0,并将lava对象的引用压到栈中

(4)调用lava的flow()方法

好了,大致了解了方法区的内容后,让我们来看看堆

Java对象的堆实现:

Java对象主要由实例变量(包括自己所属的类和其父类声明的)以及指向方法区中类数据的指针,指向方法表的指针,对象锁(非必需),等待集合(非必 需),GC相关的数据(非必需)(主要视GC算法而定,如对于标记并清除算法,需要标记对象是否被引用,以及是否已调用finalize()方法)。

那么为什么Java对象中要有指向类数据的指针呢?我们从几个方面来考虑

首先:当程序中将一个对象引用转为另一个类型时,如何检查转换是否允许?需用到类数据

其次:动态绑定时,并不是需要引用类型,而是需要运行时类型,

这里的迷惑是:为什么类数据中保存的是实际类型,而非引用类型?这个问题先留下来,我想在后续的读书笔记中应该能明白

指向方法表的指针:这里和C++的VTBL是类似的,有利于提高方法调用的效率

对象锁:用来实现多个线程对共享数据的互斥访问

等待集合:用来让多个线程为完成共同目标而协调功过。(注意Object类中的wait(),notify(),notifyAll()方法)。

Java数组的堆实现:数组也拥有一个和他们的类相关联的Class实例,具有相同dimension和type的数组是同一个类的实例。数组类名的表 示:如[[LJava/lang/Object表示Object[][],[I表示int[],[[[B表示byte[][][]

至此,堆已大致介绍完毕,下面来介绍程序计数器和Java栈

 

程序计数器:为每个线程独有,在线程启动时创建,

 

若thread执行Java方法,则PC保存下一条执行指令的地址。

 

若thread执行native方法,则Pc的值为undefined

 

Java栈:Java栈以帧为单位保存线程的运行状态,Java栈只有两种操作,帧的压栈和出栈。

 

每个帧代表一个方法,Java方法有两种返回方式,return和抛出异常,两种方式都会导致该方法对应的帧出栈和释放内存。

 

帧的组成:局部变量区(包括方法参数和局部变量,对于instance方法,还要首先保存this类型,其中方法参数按照声明顺序严格放置,局部变量可以任意放置),操作数栈,帧数据区(用来帮助支持常量池的解析,正常方法返回和异常处理)。

 

本地方法栈:依赖于本地方法的实现,如某个JVM实现的本地方法借口使用C连接模型,则本地方法栈就是C栈,可以说某线程在调用本地方法时,就进入了一个不受JVM限制的领域,也就是JVM可以利用本地方法来动态扩展本身。

相信大家都明白JVM是什么了吧

Java虚拟机工作原理详解 (一)

Java虚拟机工作原理详解 (一)

一、类加载器

首先来看一下java程序的执行过程。

%title插图%num

从这个框图很容易大体上了解java程序工作原理。首先,你写好java代码,保存到硬盘当中。然后你在命令行中输入

  1. javac YourClassName.java

此时,你的java代码就被编译成字节码(.class).如果你是在Eclipse IDE或者其他开发工具中,你保存代码的时候,开发工具已经帮你完成了上述的编译工作,因此你可以在对应的目录下看到class文件。此时的class文 件依然是保存在硬盘中,因此,当你在命令行中运行

  1. java YourClassName

就完成了上面红色方框中的工作。JRE的来加载器从硬盘中读取class文件,载入到系统分配给JVM的内存区域–运行数据区(Runtime Data Areas). 然后执行引擎解释或者编译类文件,转化成特定CPU的机器码,CPU执行机器码,至此完成整个过程。

接下来就重点研究一下类加载器究竟为何物?又是如何工作的?

首先看一下来加载器的一些特点,有点抽象,不过总有帮助的。

》》层级结构

类加载器被组织成一种层级结构关系,也就是父子关系。其中,Bootstrap是所有类加载器的父亲。如下图所示:

%title插图%num

–Bootstrap class loader:

当运行java虚拟机时,这个类加载器被创建,它加载一些基本的java API,包括Object这个类。需要注意的是,这个类加载器不是用java语言写的,而是用C/C++写的。

–Extension class loader:

这个加载器加载出了基本API之外的一些拓展类,包括一些与安全性能相关的类。(目前了解得不是很深,只能笼统说,待日后再详细说明)

–System Class Loader:

它加载应用程序中的类,也就是在你的classpath中配置的类。

–User-Defined Class Loader:

这是开发人员通过拓展ClassLoader类定义的自定义加载器,加载程序员定义的一些类。

》》委派模式(Delegation Mode)

仔细看上面的层次结构,当JVM加载一个类的时候,下层的加载器会将将任务委托给上一层类加载器,上一层加载检查它的命名空间中是否已经加载这个 类,如果已经加载,直接使用这个类。如果没有加载,继续往上委托直到顶部。检查完了之后,按照相反的顺序进行加载,如果Bootstrap加载器找不到这 个类,则往下委托,直到找到类文件。对于某个特定的类加载器来说,一个Java类只能被载入一次,也就是说在Java虚拟机中,类的完整标识是 (classLoader,package,className)。一个雷可以被不同的类加载器加载。

%title插图%num

举个具体的例子来说明,现在加入我有一个自己定义的类MyClass需要加载,如果不指定的话,一般交App(System)加载。接到任务 后,System检查自己的库里是否已经有这个类,发现没有之后委托给Extension,Extension进行同样的检查,发现还是没有继续往上委 托,*顶层的Boots发现自己库里也没有,于是根据它的路径(Java 核心类库,如java.lang)尝试去加载,没找到这个MaClass类,于是只好(人家看好你,交给你完成,你无能为力,只好交给别人啦)往下委托给 Extension,Extension到自己的路径(JAVA_HOME/jre/lib/ext)是找,还是没找到,继续往下,此时System加载 器到classpath路径寻找,找到了,于是加载到Java虚拟机。

现在假设我们将这个类放到JAVA_HOME/jre/lib/ext这个路径中去(相当于交给Extension加载器加载),按照同样的规则, *后由Extension加载器加载MyClass类,看到了吧,统一各类被两次加载到JVM,但是每次都是由不同的ClassLoader完成。

》》可见性限制

下层的加载器能够看到上层加载器中的类,反之则不行,也就是是说委托只能从下到上。

》》不允许卸载类

类加载器可以加载一个类,但是它不能卸载一个类。但是类加载器可以被删除或者被创建。

当类加载完毕之后,JVM继续按照下图完成其他工作:

%title插图%num

框图中各个步骤简单介绍如下:

Loading:文章前面介绍的类加载,将文件系统中的Class文件载入到JVM内存(运行数据区域)

Verifying:检查载入的类文件是否符合Java规范和虚拟机规范。

Preparing:为这个类分配所需要的内存,确定这个类的属性、方法等所需的数据结构。(Prepare a data structure that assigns the memory required by classes and indicates the fields, methods, and interfaces defined in the class.)

Resolving:将该类常量池中的符号引用都改变为直接引用。(不是很理解)

Initialing:初始化类的局部变量,为静态域赋值,同时执行静态初始化块。

那么,Class Loader在加载类的时候,究竟做了些什么工作呢?

要了解这其中的细节,必须得先详细介绍一下运行数据区域。

二、运行数据区域

Runtime Data Areas:当运行一个JVM示例时,系统将分配给它一块内存区域(这块内存区域的大小可以设置的),这一内存区域由JVM自己来管理。从这一块内存中分 出一块用来存储一些运行数据,例如创建的对象,传递给方法的参数,局部变量,返回值等等。分出来的这一块就称为运行数据区域。运行数据区域可以划分为6大 块:Java栈、程序计数寄存器(PC寄存器)、本地方法栈(Native Method Stack)、Java堆、方法区域、运行常量池(Runtime Constant Pool)。运行常量池本应该属于方法区,但是由于其重要性,JVM规范将其独立出来说明。其中,前面3各区域(PC寄存器、Java栈、本地方法栈)是 每个线程独自拥有的,后三者则是整个JVM实例中的所有线程共有的。这六大块如下图所示:

%title插图%num

》PC计数器:

每一个线程都拥有一个PC计数器,当线程启动(start)时,PC计数器被创建,这个计数器存放当前正在被执行的字节码指令(JVM指令)的地址。

》Java栈:

同样的,Java栈也是每个线程单独拥有,线程启动时创建。这个栈中存放着一系列的栈帧(Stack Frame),JVM只能进行压入(Push)和弹出(Pop)栈帧这两种操作。每当调用一个方法时,JVM就往栈里压入一个栈帧,方法结束返回时弹出栈 帧。如果方法执行时出现异常,可以调用printStackTrace等方法来查看栈的情况。栈的示意图如下:

%title插图%num

OK。现在我们再来详细看看每一个栈帧中都放着什么东西。从示意图很容易看出,每个栈帧包含三个部分:本地变量数组,操作数栈,方法所属类的常量池引用。

》局部(本地)变量数组:

局部(本地)变量数组中,从0开始按顺序存放方法所属对象的引用、传递给方法的参数、局部变量。举个例子:

 

  1. public void doSomething(int a, double b, Object o) {  
  2. }

这个方法的栈帧中的局部变量存储的内容分别是:

  1. 0: this  
  2. 1: a  
  3. 2,3:b  
  4. 4:0  

看仔细了,其中double类型的b需要两个连续的索引。取值的时候,取出的是2这个索引中的值。如果是静态方法,则数组第0个不存放this引用,而是直接存储传递的参数。》操作数栈:

操作数栈中存放方法执行时的一些中间变量,JVM在执行方法时压入或者弹出这些变量。其实,操作数栈是方法真正工作的地方,执行方法时,局部变量数组与操作数栈根据方法定义进行数据交换。例如,执行以下代码时,操作数栈的情况如下:

 

  1. int a = 90;  
  2. int b = 10;  
  3. int c = a + b;  

%title插图%num

注意在这个图中,操作数栈的地步是在上边,所以先压入的100位于上方。可以看出,操作数栈其实是一个数据临时存储区,存放一些中间变量,方法结束了,操作数栈也就没有啦。

》栈帧中数据引用:

除了局部变量数组和操作数栈之外,栈帧还需要一个常量池的引用。当JVM执行到需要常量池的数据时,就是通过这个引用来访问常量池的。栈帧中的数据 还要负责处理方法的返回和异常。如果通过return返回,则将该方法的栈帧从Java栈中弹出。如果方法有返回值,则将返回值压入到调用该方法的方法的 操作数栈中。另外,数据区中还保存中该方法可能的异常表的引用。下面的例子用来说明:

  1. class Example3C{  
  2.     public static void addAndPrint(){  
  3.         double result = addTwoTypes(1,88.88);  
  4.         System.out.println(result);
  5.     }
  6.     public static double addTwoTypes(int i, double d){  
  7.     return i+d;  
  8.     }
  9. }

执行上述代码时,Java栈如下图所示:%title插图%num

花些时间好好研究上图。一样需要注意的是,栈的底部在上方,先押人员addAndPrint方法的栈帧,再压入addTwoTypes方法的栈帧。上图*右边的文字说明有错误,应该是addTwoTypes的执行结果存放在addAndPrint的操作数栈中。

》》本地方法栈

当程序通过JNI(Java Native Interface)调用本地方法(如C或者C++代码)时,就根据本地方法的语言类型建立相应的栈。

》》方法区域

方法区域是一个JVM实例中的所有线程共享的,当启动一个JVM实例时,方法区域被创建。它用于存运行放常量池、有关域和方法的信息、静态变量、类 和方法的字节码。不同的JVM实现方式在实现方法区域的时候会有所区别。Oracle的HotSpot称之为永久区域(Permanent Area)或者永久代(Permanent Generation)。

》》运行常量池

这个区域存放类和接口的常量,除此之外,它还存放方法和域的所有引用。当一个方法或者域被引用的时候,JVM就通过运行常量池中的这些引用来查找方法和域在内存中的的实际地址。

》》堆(Heap)

堆中存放的是程序创建的对象或者实例。这个区域对JVM的性能影响很大。垃圾回收机制处理的正是这一块内存区域。

所以,类加载器加载其实就是根据编译后的Class文件,将java字节码载入JVM内存,并完成对运行数据处于的初始化工作,供执行引擎执行。

三、 执行引擎(Execution  Engine)

类加载器将字节码载入内存之后,执行引擎以Java 字节码指令为但愿,读取Java字节码。问题是,现在的java字节码机器是读不懂的,因此还必须想办法将字节码转化成平台相关的机器码。这个过程可以由 解释器来执行,也可以有即时编译器(JIT Compiler)来完成。

google三件套是什么_什么是Google?

google三件套是什么

Google is an American technology company that is well known for its search engine, Android operating system, Gmail mail service, GDrive cloud storage. Google started with a search engine which made it very popular and rich. In the ongoing years, Google created different technologies, services, and products. Google’s official name or the parent company is Alphabet Inc. which is established in 2015.

Google是一家美国科技公司,以其搜索引擎,Android操作系统,Gmail邮件服务,GDrive云存储而闻名。 Google从搜索引擎开始,这使其变得非常流行和丰富。 在过去的几年中,谷歌创造了不同的技术,服务和产品。 Google的正式名称或母公司是Alphabet Inc.(成立于2015年)。

谷歌历史 (Google History)

Google started in January 1996 as a research project by “Larry Page” and “Sergey Brin”. The domain name for the Google is registered on September 15, 1997, and the company incorporated on September 4, 1998. As an interesting event, Google was initially funded in August 1998 about $100,000 by Andy Bechtolsheim before incorporation.

Google于1996年1月作为“拉里·佩奇”和“谢尔盖·布林”的研究项目开始。 Google的域名于1997年9月15日注册,公司于1998年9月4日注册成立。有趣的是,Google在1998年8月*初由Andy Bechtolsheim出资约100,000美元成立。

Google also received money from Amazon founder Jeff Bezos, Professor David Cheriton, and entrepreneur Ram Shriram which is in total 1 million dollars. At the end of 1998 to early 1999, a new $25 million funding also received from venture capital firms.

谷歌还从亚马逊创始人杰夫·贝索斯(Jeff Bezos),大卫·切里顿(David Cheriton)教授和企业家拉姆·史里拉姆(Ram Shriram)那里获得了总计100万美元的投资。 在1998年底至1999年初,还从风险投资公司获得了2500万美元的新资金。

Google’s initial public offering (IPO) took place on August 19, 2004. This made the Google total value of about $23 billion. In October 2006, Google had acquired the popular video-sharing site YouTube for $1.65 billion.

Google的首次公开募股(IPO)于2004年8月19日进行。这使Google的总价值约为230亿美元。 2006年10月,Google以16.5亿美元的价格收购了流行的视频共享网站YouTube。

By 2011, Google was handling about 3 billion searches per day where in order to handle this request Google built 11 data centers in different locations and countries around the world. On August 15, 2011, Google made its largest acquisition to date with the “Motorola Mobility” for $12.5 billion. In 2012 Google generated $50 billion annual revenue which was $38 billion in the previous year.

到2011年,Google每天处理大约30亿次搜索,为了处理此请求,Google在全球不同位置和国家/地区建立了11个数据中心。 2011年8月15日,谷歌以125亿美元的价格进行了迄今为止*大的一笔收购,即“摩托罗拉移动性”。 2012年,Google的年收入为500亿美元,去年为380亿美元。

LEARN MORE  What Is a Web Browser?
了解更多什么是Web浏览器?

On August 10, 2015, Google reorganized its interests as Alphabet and Google became Alphabet’s leading subsidiary. With this reorganization, Sundar Pichai became CEO of Google. Google became the second most valuable brand in 2013, 2014, 2015, and 2016 behind Apple with a valuation of $133 billion.

2015年8月10日,Google重组了自己的权益,成为Alphabet,而Google成为了Alphabet的主要子公司。 通过这次重组,Sundar Pichai成为Google的首席执行官。 在2013年,2014年,2015年和2016年,谷歌以1330亿美元的估值位居第二,仅次于苹果。

On March 19, 2019, Google announced cloud gaming platform named “Stadia”.

2019年3月19日,谷歌宣布了名为“ Stadia”的云游戏平台。

%title插图%num
Google
谷歌

从Google Inc.到Alphabet Inc.(From Google Inc. To Alphabet Inc.)

As stated previously “Google Inc.” is named to the “Alphabet Inc.” in August 2015. Alphabet became the parent company of Google and other companies like “Calico”, “DeepMind”, “Google Fiber”, Waymo” etc. Alphabet Inc. 2019 revenue is about $161 billion most of them come from Google. The current CEO of Alphabet is Larry Page and Sergey Brin is the president.

如前所述,“ Google Inc.” 被命名为“ Alphabet Inc.” 2015年8月,Alphabet成为Google以及诸如“ Calico”,“ DeepMind”,“ Google Fiber”,Waymo”等其他公司的母公司。AlphabetInc. 2019年的收入约为1,610亿美元,其中大部分来自Google。 Alphabet的现任首席执行官是拉里·佩奇(Larry Page),塞吉·布林(Sergey Brin)是总裁。

Google服务 (Google Services)

Google is very big company which has variaty of services, products and technologies. Below we listed some of the most known and popular of them.

Google是一家非常庞大的公司,拥有各种服务,产品和技术。 下面我们列出了其中一些*著名和*受欢迎的。

  • Google Search Engine

    谷歌搜索引擎

  • Google Mail or Gmail

    Google Mail或Gmail

  • Google Adsense

    谷歌的AdSense

  • Android Mobile Operating System

    Android移动操作系统

  • Google Chrome

    谷歌浏览器

  • Google Translate

    谷歌翻译

  • Google Suite

    Google套件

谷歌搜索引擎(Google Search Engine)

Google Search Engine is the first services and product of the Google. Also Google Search Engine is the one of the core business of the Google. According to the comScore Google Search is most used search engine with the 65.6% market share.

Google Search EngineGoogle Search Engine的*批服务和产品。 谷歌搜索引擎也是谷歌的核心业务之一。 根据comScore,Google搜索是使用*多的搜索引擎,市场份额为65.6%。

%title插图%num
Google Search Engine
谷歌搜索引擎

Google Mail或Gmail(Google Mail or Gmail)

One of the other popular services is Google Mail or with its well-known name Gmail. Gmail provides email service with some auxiliary services like Calendar, Contacts, ToDo list, etc.

其他流行的服务之一是Google Mail或使用其知名名称Gmail。 Gmail为电子邮件服务提供了一些辅助服务,例如日历,联系人,待办事项列表等。

谷歌的AdSense (Google Adsense)

From the revenue point of view, Google Adsense is the most important business of Google. Google Adsense provides advertising business via the app, in-app purchases, digital content, etc.

从收入的角度来看,Google Adsense是Google*重要的业务。 Google Adsense通过应用程序,应用程序内购买,数字内容等提供广告业务。

LEARN MORE  How To Manage Google Chrome Extensions? Add, Install, Update, Remove Google Chrome Browser Extension
了解更多如何管理Google Chrome扩展程序? 添加,安装,更新,删除Google Chrome浏览器扩展程序

安卓系统(Android)

Google developed the most popular mobile operating system Android. Android is mainly used for smartphones but also provided by different types of consumer devices like smartwatch, television, car, IoT, etc.

Google开发了*受欢迎的移动操作系统Android。 Android主要用于智能手机,但也由智能手表,电视,汽车,物联网等不同类型的消费类设备提供。

%title插图%num
Android
安卓系统

谷歌浏览器(Google Chrome)

Google Chrome is the most popular web browser in the internet. Google Chrome supports different operating systems and platforms like Windows, Linux, Android, iOS, MacOSX etc.

Google Chrome浏览器是互联网上*受欢迎的网络浏览器。 Google Chrome支持不同的操作系统和平台,例如Windows,Linux,Android,iOS,MacOSX等。

%title插图%num
Google Chrome
谷歌浏览器

谷歌翻译(Google Translate)

Google Translate is popular translation services that are served via https://translate.google.com/. Google Translate can translate words, sentences, or complete articles. Also “.doc”, “.docx” , “.odf”, “.pdf”, “.txt”, “.xls”, “.xlsx” documents can be uploaded and translated automatically. Google Translate supports over 100 languages around the world with the help of communities.

Google Translate是流行的翻译服务,可通过https://translate.google.com/提供。 Google翻译可以翻译单词,句子或完整的文章。 此外,“。doc”,“。docx”,“。odf”,“。pdf”,“。txt”,“。xls”,“。xlsx”文档也可以自动上传和翻译。 Google翻译在社区的帮助下支持全球100多种语言。

%title插图%num
Google Translate
谷歌翻译

谷歌云(Google Cloud )

Google Cloud is an enterprise level product which is the same Amazon Web Services and Microsoft Azure. Google Cloud provide cloud services about computing, storage, database, networking, development, data analytics, AI and Machine learning, API management, security and identity, serverless computing, IoT etc.

Google Cloud是企业级产品,与Amazon Web Services和Microsoft Azure相同。 Google Cloud提供有关计算,存储,数据库,网络,开发,数据分析,AI和机器学习,API管理,安全性和身份,无服务器计算,IoT等的云服务。

%title插图%num
Google Cloud
谷歌云

Google文件和G Suite(Google Docs and G Suite)

Google Docs and G Suite provides different tools for personals and SMB’s to create, manage and share documents, corporate email address, cloud storage.

Google DocsG Suite为个人和SMB提供了不同的工具来创建,管理和共享文档,公司电子邮件地址,云存储。

%title插图%num
Google Docs and G Suite
Google文件和G Suite

kali 安装nessus_如何将持久的Nessus安装到Kali中?

kali 安装nessus

Nessus is very good tool to manage vulnerabilities or vulnerability scanning. How can I install Nessus into my dpkg based pentest box? My distro my Debian, Ubuntu, Kali etc.

Nessus是管理漏洞或漏洞扫描的非常好的工具。 如何将Nessus安装到基于dpkg的渗透测试盒中? 我的发行版包括Debian,Ubuntu,Kali等。

获取许可证密钥 (Get License Key)

First step is license key. In old days Nessus was provided by Kali distribution as home version. There was no day limit of the Nessus. But the days gone and we are now here. To use Nessus we can download a trial of 7 days or buy. I assume you have completed this step. We can complete this step with this web page

*步是许可证密钥。 过去,Kali发行版将Nessus作为家庭版提供。 Nessus没有天数限制。 但是日子已经过去了,我们现在在这里。 要使用Nessus,我们可以下载7天的试用版或购买。 我假设您已完成此步骤。 我们可以通过此网页完成此步骤

https://www.tenable.com/products/nessus/nessus-professional/evaluate

https://www.tenable.com/products/nessus/nessus-professional/evaluate

下载Nessus软件包 (Download Nessus Package)

Good we have license now. We need to get installation package. Nessus supports a lot of different operating systems from Kali to Windows. We download for Kali from this page.

好,我们现在有许可证。 我们需要获取安装包。 Nessus支持许多不同的操作系统,从Kali到Windows。 我们从此页面为Kali下载。

http://www.tenable.com/products/nessus/select-your-operating-system#tos

http://www.tenable.com/products/nessus/select-your-operating-system#tos

Download Nessus Package
Download Nessus Package
下载Nessus软件包

使用dpkg安装Nessus(Install Nessus with dpkg)

Our package download is completed. We will install the Nessus with dpkg tool. Our packages full name is Nessus-6.9.0-debian6_amd64.deb . Installation can take some time. Actually installing Nessus is fast but configuration of the plugins take some time. There are a lot of plugins for different systems. For example it took 870 second in my SSD cached Kali virtual machine.

我们的软件包下载完成。 我们将使用dpkg工具安装Nessus。 我们的软件包全名是Nessus-6.9.0-debian6_amd64.deb。 安装可能需要一些时间。 实际上,安装Nessus的速度很快,但配置插件需要一些时间。 有很多用于不同系统的插件。 例如,在我的SSD缓存Kali虚拟机中花费了870秒。

  1. $ dpkg -i Nessus-6.9.0-debian6_amd64.deb
  2. (Reading database … 404642 files and directories currently installed.)
  3. Preparing to unpack Nessus-6.9.0-debian6_amd64.deb …
  4. Unpacking nessus (6.9.0) …
  5. Setting up nessus (6.9.0) …
  6. Unpacking Nessus Core Components…
  7. nessusd (Nessus) 6.9.0 [build M20070] for Linux
  8. Copyright (C) 19982016 Tenable Network Security, Inc
  9. Processing the Nessus plugins…
  10. [##################################################]
  11. All plugins loaded (870sec)
  12. – You can start Nessus by typing /etc/init.d/nessusd start
  13. – Then go to https://kali:8834/ to configure your scanner
  14. Processing triggers for systemd (231-9) …

Keep in mind that to install we need root privileges. After installation it gives helpfull information about.

请记住,要安装,我们需要root特权。 安装后,它会提供有用的信息。

LEARN MORE  List and Change Kernel Config Variables With Sysctl Command
了解更多信息使用Sysctl命令列出和更改内核配置变量

启动Nessus服务(Start Nessus Service)

After installing Nessus we should do some configuration. Nessus is not started by default. So we should start Nessus with the following command.

安装Nessus之后,我们应该进行一些配置。 Nessus默认情况下未启动。 因此,我们应该使用以下命令启动Nessus。

  1. $ /etc/init.d/nessusd start
  2. Starting Nessus : .

We have started nessusd service but be sure it is running by checking service status.

我们已经启动了nessusd服务,但是请通过检查服务状态来确保它正在运行。

  1. $ /etc/init.d/nessusd status
  2. Nessus is running

登录到Nessus Web界面 (Login To Nessus Web Interface)

If the Nessus service is working properly we can login to the Nessus from web interface. Nessus uses TCP port 8443 by default but it can be changed. We will also use https for security reasons.

如果Nessus服务正常运行,我们可以从Web界面登录Nessus。 Nessus默认使用TCP端口8443 ,但可以更改。 出于安全原因,我们还将使用https 。

https://localhost:8443

After accessing web page we can enter license key

访问网页后,我们可以输入许可证密钥

如何将持久的Nessus安装到Kali中? 信息移植 (How To Install Tenable Nessus into Kali? Infografic)

How To Install Tenable Nessus into Kali? Infografic
How To Install Tenable Nessus into Kali? Infografic
如何将持久的Nessus安装到Kali中? 信息移植

ubuntu添加路由_如何在Ubuntu,Linux中添加新路由?

ubuntu添加路由

ubuntu添加路由

I have a box with Ubuntu Linux and I want to add a new route to my box. Because I want to access an external network from a different interface and network. How can I add a new route to my Ubuntu, Debian, Fedora, Cent-OS Linux box? Because ip-tools is the same for all of these Linux distributions.

我有一个装有Ubuntu Linux的盒子,我想向盒子中添加一条新路由。 因为我想从其他接口和网络访问外部网络。 如何在我的Ubuntu,Debian,Fedora,Cent-OS Linux盒中添加新路由? 因为ip-tools对于所有这些Linux发行版都是相同的。

使用ip命令显示/列出现有路由表和信息 (Display/List Existing Routing Table and Information By Using ip Command)

First, we should display existing routing table. Our target network should not intersect existing routing information. The routing table contains different routes to the remote networks with the same or different gateways. In general, the same default gateway is used.

首先,我们应该显示现有的路由表。 我们的目标网络不应与现有的路由信息​​相交。 路由表包含到具有相同或不同网关的远程网络的不同路由。 通常,使用相同的默认网关。

$ ip route show
Display Existing Routing Table
Display Existing Routing Table
显示现有路由表

We can see that there is a default route that is listed in the first line. It also named as default . The default gateway IP address is 192.168.142.2

我们可以看到*行列出了默认路由。 它也被命名为default 。 默认网关IP地址为192.168.142.2

使用route命令显示/列出现有路由表和信息 (Display/List Existing Routing Table and Information By Using route Command)

Linux provides alternative ways and commands to list the existing routing tables and information. We can use the command route in order to list the existing routing table with information like destination, gateway, netmask, flags, metric, interface. route command is provided by the net-tools in Ubuntu which is not installed by default. We can install the net-tools package with the following command to use route command.

Linux提供了其他方法和命令来列出现有的路由表和信息。 我们可以使用命令route来列出现有的路由表,其中包含诸如目的地,网关,网络掩码,标志,度量,接口之类的信息。 route命令由Ubuntu中的net-tools提供,默认情况下未安装。 我们可以使用以下命令安装net-tools软件包以使用route命令。

$ sudo apt install net-tools
%title插图%num
Install net-tools Package For route Command
为路由命令安装net-tools软件包

We will only type the command route to the Linux shell.

我们将只键入到Linux Shell的命令route 。

$ route
%title插图%num
List Route Information with route Command
使用route命令列出路线信息

使用netstat命令显示/列出现有路由表和信息(Display/List Existing Routing Table and Information By Using netstat Command)

Alternatively, the command netstat can be also used to list the routing table and information. In order to list routing information the options -n and -r should be provided to the command netstat.

或者,也可以使用命令netstat列出路由表和信息。 为了列出路由信息,应该在命令netstat中提供选项-n-r 。

$ netstat -nr

使用ip命令添加新路由 (Add New Route with ip Command)

In order to add a new route, we will use the command ip route add by providing related information. We will add a new route to the 172.16.0.0/16 network.

为了添加新路由,我们将通过提供相关信息使用命令ip route add 。 我们将向172.16.0.0/16网络添加一条新路由。

$ sudo ip route add 172.16.0.0/24 via 192.168.122.1 dev ens3
  • ip route add  is our command to add a new route.

    ip route add是我们的命令,用于添加新路由。

  • 172.16.0.0/24 is a target network that is the destination range.

    172.16.0.0/24是作为目标范围的目标网络。

  • via 192.168.122.1 specifies the next hoop which should be directly connected to our system network.

    通过192.168.122.1指定应该直接连接到我们的系统网络的下一个箍。

  • dev ens3 specifies our interface which is the same network with 192.168.122.1

    dev ens3指定我们的接口,该接口与192.168.122.1是同一网络

LEARN MORE  How To Start, Stop, Restart Networking On Linux?
了解更多如何在Linux上启动,停止,重新启动网络?

使用route命令添加新路线 (Add New Route By Using route Command)

Alternatively, we can add a new route by using the command route. We will use the option add of the route command where also provide other parameters like destination network, gateway, and interface name. In the following example, we will add a route to the network 10.0.0.0 by using the -net option by setting 192.168.1.1 as gateway for the interface eth0.

另外,我们可以使用命令route添加新路由。 我们将使用route命令的选项add ,其中还提供其他参数,例如目标网络,网关和接口名称。 在以下示例中,我们将通过使用-net选项(将192.168.1.1设置为接口eth0网关)使用-net选项添加到网络10.0.0.0的路由。

$ sudo route add -net 10.0.0.0/8 gw 192.168.1.1 eth0

检查新路线 (Check New Route)

A newly added route will be activated instantly after adding the routing table. We can also list and check the newly added route information by using the command ip route show like below. We will see that the new route is added successfully.

添加路由表后,将立即激活新添加的路由。 我们还可以使用以下命令ip route show列出并检查新添加的路由信息​​。 我们将看到新路由已成功添加。

  1. $ ip route show
  2. default via 192.168.122.1 dev ens3
  3. 10.0.3.0/24 dev lxcbr0  proto kernel  scope link  src 10.0.3.1
  4. 172.16.0.0/24 via 192.168.122.1 dev ens3
  5. 192.168.122.0/24 dev ens3  proto kernel  scope link  src 192.168.122.211

使用route命令删除/删除现有路由 (Delete/Remove Existing Route By Using route Command)

We can delete an existing route by using the command route. It is very similar to the adding route where we will replace the add options with the del option.

我们可以使用命令route删除现有路由。 这与添加路由非常相似,在添加路由中,我们将用del选项替换add选项。

$ sudo route del -net 10.0.0.0/8 gw 192.168.1.1 eth0

You can use the following infographic in order to get brief information about adding new routes for Linux and Ubuntu.

您可以使用以下信息图来获取有关为Linux和Ubuntu添加新路由的简要信息。

How To Add New Route In Ubuntu, Linux? Infografic
How To Add New Route In Ubuntu, Linux? Infographic
如何在Ubuntu,Linux中添加新路由? 信息图
友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速