JAVA教程--书的

第一个java程序

public class HelloWorld {
//所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
    public static void main(String[] args) { //这里可通过 java 类名 hello world ! 传入参数
    
        System.out.println("Hello World");
    }
}

在这里插入图片描述

String args[] 与 String[] args 都可以执行,但推荐使用 String[] args,这样可以避免歧义和误读。前一种主要是为了和C++对齐
两个S是都是大写 System 和String syso快捷
一个文件中可有多个类 但是文件名应该和public声明的类保持一致

javac HelloWorld.java
//如果遇到编码问题,我们可以使用 -encoding 选项设置 utf-8 来编译:
//javac -encoding UTF-8 HelloWorld.java 
java HelloWorld 

环境配置—网上更详细

x64 Compressed Archive 是压缩包 一般安

classPath的作用是使用java 类名运行java程序时,搜索这个类的路径(class文件的存放搜索地址 ),jdk1.4之后可默认在当前文件夹下搜索,所以之后的版本都不需要指定classpath了
Path则是告诉java这个命令的位置

javac -d的意思是,按照package的文件夹排列 生成对应的class文件,所以,其实并不需要将java源文件按照package的顺序去放,但是为了方便 还是----
如果使用package打包 那么运行java文件的时候 就要用 java 包名.类(因为打包的时候会在当前目录自动生成文件夹)

命名规范

  • 所有的标识符都应该以英文字母,美元符( ) 、 或 者 下 划 线 ( ) 开 始 , 注 : )、或者下划线(_)开始,注: 线an是合法的
  • 包名 小写字母
  • 类名:首字母大写,例如 MyFirstJavaClass 。
  • 方法名 首字母小写驼峰式
  • 普通变量 都小写,连字符连接吧
  • 常量 纯大写
  • 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
    如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。

变量种类

类变量(静态变量)声明在类中,方法体之外,但必须声明为 static 类型。
成员变量(非静态变量)属于对象而不属于类
局部变量

Java 枚举

Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。

例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁。

实例

class FreshJuice {
   enum FreshJuiceSize{ SMALL, MEDIUM , LARGE }
   FreshJuiceSize size;
}
 
public class FreshJuiceTest {
   public static void main(String[] args){
      FreshJuice juice = new FreshJuice();
      juice.size = FreshJuice.FreshJuiceSize.MEDIUM  ;
   }
}

数据类型

基本数据类型

除了Sring是大写,且是引用类型;
注:char是单引号,String是双引号

运算

0/0是NaN
1/0是Infinity
-1/0是-Infinity

equal和==

equal判断值是否相等,==判断引用是否相同(引用类型时)

取值范围

对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了。请看下面的例子:

System.out.println(“基本类型:byte 二进制位数:” + Byte.SIZE);
System.out.println(“包装类:java.lang.Byte”);
System.out.println(“最小值:Byte.MIN_VALUE=” + Byte.MIN_VALUE);
System.out.println(“最大值:Byte.MAX_VALUE=” + Byte.MAX_VALUE);
System.out.println();

注 此处开头是大写

默认值

只列出比较特殊的
char ‘u0000’
String (or 任何对象) null
boolean false

需要注意的是局部变量没有默认值,必须指定。编程时候都指定值即可

可使用下划线分割大数字防止看花眼

如1000_1000;3.14_15_926

引用类型

对象、数组都是引用数据类型。
所有引用类型的默认值都是null。
一个引用变量可以用来引用任何与之兼容的类型。
例子:Site site = new Site(“Runoob”)。

自动类型转化

整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。

转换从低级到高级。char(或者byte->short)->int->long->float->double

注意事项

  1. 不能对boolean类型进行类型转换
  2. 不同类型的可转化,char可自动类型转换为int(通过ascii码表的值 而非本来的值
  3. 不能把对象类型转换成不相关类的对象。
  4. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
  5. 转换过程中可能导致溢出或损失精度
  6. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入

隐含强制类型转换

1、 整数的默认类型是 int。定义long时需要后面加L或l,通常建议大写防止和数字1混淆。

  1. 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。

表达式类型的自动提升–经典错误

short a=5;
a = a-2;//错误 因为2默认是int 会提升会int 赋给short类型
当两个int类型相除,赋给int类型时候,是直接取整而非四舍五入

自动装箱,拆箱

比如当用到数字长度等属性时,需要对象类。如toStrng等方法

Integer x = 5;

String本身就是一个对象
char和Character 不是简单的大写首字母

String类----比较特殊 单独拆出来

String本身就是一个对象

两种创建方式区别
String str = "Runoob";
String str2=new String("Runoob");

String s1 = "Runoob";              // String 直接创建
String s2 = "Runoob";              // String 直接创建
String s3 = s1;                    // 相同引用
String s4 = new String("Runoob");   // String 对象创建
String s5 = new String("Runoob");   // String 对象创建

在这里插入图片描述

注意:String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。

+连接字符串
length()输出长度
格式化字符串

System.out.printf("浮点型变量的值为 " +
                  "%f, 整型变量的值为 " +
                  " %d, 字符串变量的值为 " +
                  "is %s", floatVar, intVar, stringVar);
你也可以这样写

String fs;
fs = String.format("浮点型变量的值为 " +
                   "%f, 整型变量的值为 " +
                   " %d, 字符串变量的值为 " +
                   " %s", floatVar, intVar, stringVar);

Java StringBuffer 和 StringBuilder 类

当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

        StringBuilder sb = new StringBuilder(10);
        sb.append("Runoob..");

可自动扩容

转义字符

Java语言支持一些特殊的转义字符序列。

符号 字符含义
\n 换行 (0x0a)
\r 回车 (0x0d)
\f 换页符(0x0c)
\b 退格 (0x08)
\0 空字符 (0x0)
\s 空格 (0x20)
\t 制表符
" 双引号
’ 单引号
\ 反斜杠
\ddd 八进制字符 (ddd)
\uxxxx 16进制Unicode字符 (xxxx)

java修饰符----一般关注private和public即可

分类

访问修饰符
非访问修饰符

默认访问修饰符

变量和方法:default
接口-变量都隐式声明为 public static final,
接口-方法默认情况下访问权限为 public。

访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被子类继承。

增强型for循环–foreach

int [] numbers = {10, 20, 30, 40, 50};
      for(int x : numbers ){
         System.out.print( x );
      }

Java Math 类

Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。

Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。

数组

若需要长度可变的结构,使用Vector

数组作为函数的返回值

public static int[] reverse(int[] list) {
  int[] result = new int[list.length];
 
  for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
    result[j] = list[i];
  }
  return result;
}

多维数组

多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:

int[][] str = new int[3][4];

但是,java的二维数组其实是一维数组,str[1]中存的其实是一个引用地址,而非int的值本身
不能把java扩充为三维数组 四维度 像其他语言那样,因为已经制定了a【0】的数组元素为int,如果需要这样做,请将其指定为Object类型

length不加括号,是数组的属性

日期时间类

https://www.runoob.com/java/java-date-time.html

java方法

System.out.println()

println() 是一个方法。
System 是系统类。
out 是标准输出对象。
这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。

可变参数

JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。

方法的可变参数的声明如下所示:

typeName… parameterName
在方法声明中,在指定参数类型后加一个省略号(…) 。

finalize() 方法

Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。

例如,你可以使用 finalize() 来确保一个对象打开的文件被关闭了。

方法的参数(形参)传递

方法的参数传递为值传递
1、当参数是普通类型时–易理解
如void add(int a){a=a+1}而没有return输出时,仅仅是函数里面的a变了 外面的a是不变的。
2、当参数是引用类型时,分两种情况
2.1、当试图更改引用的地址,如string类型 s1= s1+“aaa”;函数内部的s1会指向一个新的地址(String的特性),函数外面的s1不变(不可见)
2.2、当不改变引用,改变的是引用的数据 如StringBuffer类型 s2 = s2.append(“bbb”) 则对外部是可见的,外面的s2也会变

java面向对象–独立出来 见另一个blog

垃圾回收

垃圾回收只能回收内存资源,对其他物理资源,如数据库连接、磁盘io等无能为力
为了更快使用垃圾回收机制,可以将对象的引用变量设置为null,暗示垃圾回收机制回收对象
可使用runtime对象的gc方法建议回收垃圾,不过用的不多

applet

嵌入浏览器中,可快速运行,大多数浏览器支持这种写法,但是其实必须要用java图形化 ,放弃吧

图形化gui

awt和swing已经被javafx替代了,但是资料比较少。尽量还是别用java开发图形化界面吧

可用金山,WTL,QT,MFC(自绘),WPF等

输入输出

输出的S是大写
输入:

import java.util*;
xxx
Scanner reader = new Scanner(System.in);//输入并不在此处 只是申明
syso("Enter your name:");
String name = reader.next();//此时用户的输入会按回车后被输入到这里  next方法读取一整行的字符
int age=reader.nextInt();//读入一个整数数据

others

jphp可将php编译为java
java使用unicode字符集
break和continue可带标号

方法的参数传递(其实就是引用传参和值传参)

public class FunctionArgs{
    public static void main(String[] args){
        String a = new String("java");
        StringBuffer b = new StringBuffer("java");
        changeS(a,b);
        System.out.println(a);//java
        System.out.println(b);//javachange
    }
    //若只想写示例程序,声明为static可减少代码量
    public static void changeS(String a ,StringBuffer b){
        a +="change";
        b.append("change");
    }
}

java常用的包

java.lang 基本语言类 自动引入
java.io 输入输出
java.util 数据类型类
java.net 网络功能类

其他

形参可变的写法 ,如 public void test(int a ,String…books)
java 局部代码块,即用{}包裹起来的 里面定义的变量 在括号外不可见,这个其实叫初始化快,会比构造器更早运行
好处1:如有多个构造器,就要在多个地方加上初始化函数完成初始化工作,而如果放到初始化块中的话则只要写一次即可(如判断是否登录?);

public class Car
{
   private void init()
   {
      System.out.println("Start engine before run()");
   }
    
   //使用初始化块
   {
     init();
    }
  
 
   public Car()
   {
      //init();
      System.out.println("Run normally");
   }
   
   public Car(float velocity)
   {
      //init();
      System.out.println("Run with "+velocity+" miles/h");
    }
 
   public static void main(String[]args)
   {
      new Car();
      new Car(210f);
   }
}

好处2:但是,如果只是这一点便利的话,还不足以使用初始化块,其实初始化块真正体现其独一无二的作用是在匿名内部类中,由于是匿名内部类,因而无法写构造方法,但是很多时候还是要完成相应的初始化工作,这时就需要用到初始化块了,特别是Android中大量地使用匿名内部类,初始化块的作用就十分突出

静态初始化快,static{} 会在类首次加载的时候运行,所以比在创建对象时候运行的普通初始化快更早运行

java自动装箱

java整个语言都是面向对象的,除了int这些基本类型,方便其他语言的程序员使用。所以它们是大写。String本身就是对象 所以大写
为了贯彻一切都是对象,提供了对应的包装类,可自动拆箱等
Integer a=5;//自动装箱,把基本类型赋给包装类
int b = a;//自动拆箱
除此之外,包装类还可实现基本类型变量和字符串的相互转化。

String a = "123"
int a1 = Integer.parseInt(a);//法1
int a2 = new Integer(a);//法2
String str = String.valueOf(true)//String类特殊 用这个
String str1 = 5+”“;//string还可这样把数值类型转化过来

注意:当使用包装类时,判断两个值相同的包装类,用==会判断false,equals是true;如果大小判断可以用静态的compare方法,如Integer.compare(a,b)
但是一个包装类和一个基本类型是可以相互比较的
String类重写了equal
ps:instanceof 父类也会返回true 所以,重写equal方法要用到反射的getClass方法

java对象打印

通过重写toString方法,里面return出对象的自我描述,就可以通过syso打印出来自定义的描述

IO

IO流分类

1输入流与输出流

首先定义输入和输出,输入输出都是从内存的角度来说的。
输入是指从其他地方到内存,输出是指从内存到其他地方,如硬盘。

2、字节流和字符流

字节流的处理对象是8位的字节,而字符流的处理对象是16位的字符。
字符流的实质也是字节流,但是为了处理的方便……。能用记事本打开的东西都是字符流!

3、节点流与处理流

节点流较低级,是想一个特定的设备读取的流。
而处理流较高级,也被成为包装流,比如和数据库连接,处理流是统一的,而具体的节点流可能流向Mysql、oracle数据库。有点像jvm,无需针对每个操作系统编写java代码
注:名字有file的一般是节点流,有print的一般是处理流

具体介绍

输入流:InputStream(字节流)和Reader(字符流)
输出流:OutputStream和Writer
上面四个类是所有输入输出流的基类,是抽象类,不可直接实例化。
分别有read 和 write方法

使用示例

FileInputStream fis = new FileInputStream("xxx.java")
byte[] bbuf = new byte[1024];//竹筒
int hasRead = 0;//记录读取的字节数
while((hasRead = fis.read(bbuf))>0){
Syso(new String(bbuf,0,hasRead))
}
fis.close();//用完必须关闭

可用try语句的括号语法 保证输出流一定被关闭,需要catch IoException!
注:关闭输出流的时候,会自动调用flash()和close()方法,其中flush会将输出流缓冲区中的数据flush到物理节点,所有用的时候要注意正常使用,一般正常使用即可保证程序正常。

处理流的用法
FileInputStream fis = new FileInputStream("xxx.java")
PrintStream ps = new PrintStream(fos);
//识别处理流很简单,只要构造器c桉树不是具体的物理节点就行,甚至字符串也是物理节点


转换流

java只提供字节流像字符流的转换,因为正常不会反过来转换,用法,如读取键盘输入system.in,普通的Reader读取输入内容的时候依然不太方便,可以将普通的Reader包装成BufferdReader,利用readLine方法可以一次读取一行数据

InputStreamReader reader = new ……(system.in);//将键盘输入转换为Reader对象
BufferedReader = new ^(reader); 然后就能用readLine方法了

File类

file类能新建删除 重命名文件和目录 但是不能访问文件内容本身!需要使用输入 输出流。
Windows路径分隔符为\ ,由于转义字符,要用两条反斜线,或者直接使用斜线/

重定向

java标准输入输出 System.in 和 System.out 正常情况下代表键盘和屏幕
如果要改变 可以用重定向方法 如 setIn、setOut

RA

RandomAccessFile和普通的输入输出流不同的是,它可以直接跳到文件的任意地方来独写数据。
注,RAM是内存 应该翻译成任意访问 而非随机访问!翻译的问题导致难以理解。

对象序列化—详细的以后再看

类实现了Serializable接口,则可序列号,可通过网络、磁盘传输。

文件锁

可加锁防止脏读等冲突问题

NIO(new IO)-----以后再找李刚的书看

jdk1.4开始提供了一种新的方式,采用内存映射的方式处理输入输出,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样访问文件了,比之前快了很多。

JAVA7 改进了nio 称为NIO2

其他

Scanner也可获取键盘输入
缓冲流类似cache 当缓存满了后一次性从缓存中输出或输入

Java基础类库

Runtime类代表JAVA程序运行时的环境
StringBuider类和StringBuffer类基本相同,不同的是前者没有线程安全,所以性能略高,一般情况优先考虑buider
Random类用于生成随机数
时间有DATE和calendar,后者更先进 但是略难用 前者设计不好。JAVA8 又新增了一个java.time的包
java可使用国际化 针对不同语言进行编译
java还有日期格式化等东西

Java集合

为什么需要集合?传统的java数组,由于有固定的长度,无法动态拓展,且无法报错具有映射关系的数组(关联数组),所以需要集合

分类

List:有序可重复
Set:无序不可重复
Quene:队列
Map:关联数组
其中前三种由Collection接口派生而出,后者由Map接口派生而出

Collection接口与Iterator(迭代器,用于迭代Collection,是Collection的父接口)接口

常用方法

add:如果参数是基本类型 能够自动装箱为对象
addAll
clear 清除集合所有元素,将集合长度变为0
contains 返回集合中是否包含指定元素
containsAll 集合里是否包含指定集合里的所有元素
isEmpty
iterator 返回一个迭代器对象,用于遍历集合中的元素
remove
size
toArray

Lambda表达式遍历集合—foreach

Java8 为Interable新增了一个forEach(Consumer action)的默认方法(默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法) ,Consumer是函数式接口,所以能够使用lambda表达式。

for(int x : numbers ){}//数组的叫 for-each,其实也可用来遍历集合,比如int改成Object即可
books.forEach(obj->Syso(obj));//这样可遍历元素输出

Iterator遍历集合元素
		// 创建集合
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Zhihu");

        // 1\获取迭代器
        Iterator<String> it = sites.iterator();

        // 输出集合中的所有元素
        while(it.hasNext()) {
            System.out.println(it.next());
        }
Iterator it = books.iterator();
it.forEachRemaining(obj->Syso(obj));//这样可遍历元素输出

Iterator有四个方法
hasNext
next
remove,删除集合里上次next方法返回的元素
forEachRemaining 可使用lambda表达式遍历集合元素

注意:迭代的时候,除了用remove,不能用其他方法修改集合,否则会抛出运行时异常。

Set

HashSet:根据hash算法算出set的位置,速度很快。不保证顺序、不同步,多个线程修改HashSet需要通过代码保证同步、集合元素值可以为null;
LinkedHashSet:多使用一个链表来维护元素的插入顺序,因此性能略低于HashSet
TreeSet:是SortedSet的子类,保证元素处于排序状态,相比父类多了几个方法,且可采用自然排序和定制排序
EnumSet:
上述几个类都是线程不安全的

List

ArrayList和Vector是List的两个经典实现类,都封装了一个动态的Object【】数组
区别:Vector从JDK1.5就有了,很古老,尽量少用,但是是线程安全的。而前者是线程不安全的。其次,Vector提供了一个Stack子类,用来模拟栈这种数据结构

线性表的使用建议

1、如果要遍历List集合,对于ArrayList、Vector 应该使用使用索引的随机访问方法get来遍历,而LinkedList应该使用迭代器Iterator来遍历
2、如果需要经常插入、删除,建议用链表而非普通顺序表
3、如果多个线程需要访问List,可考虑使用Collections将集合包装成线程安全的集合。

Queue和Deque(双端队列,也可作为栈来使用)

Map–字典、关联数组

set与map的关系很密切,如果把key-value中的value当成key的附庸,那么就可以像对待set一样对待Map了。而实际上,java源码是先实现了Map,然后通过包装一个所有value都为null的Map实现了Set集合

常用子类
HashMap —类似ArrayList 线程不安全。优先被推荐使用
HashTable —类似Vector 古老但线程安全。但是即使要创建线程安全的Map实现类,也无需使用这个,而可以通过后面介绍的Collections工具类把HashMap变成线程安全的
LinkedHashMap,维护一个双向链表 保证插入次序
SortedMao 红黑树结构 分自然排序和定制排序
TreeMap
EnumMap

常用方法:
clear 删除该Map对象的所有key-value对
containsKey
containsValue
enterSet 返回Map中包含的所有key-value对所组成的set集合
get
isEmpty
keySet 返回该Map中所有key组成的Set集合
put(key,value)
putAll(Map map)
remove
values 返回所有value组成的collection

Hash的原理

可以指定创建的初始化容量、负载因子,当达到负载极限的时候,会自动增加桶的数量,然后做reHashing

操作集合的工具类-Collections (和之前的区别是多了一个s)

Collections.sort(nums);//nums是一个list集合

可使用synchronizedXXX()方法包装集合类成为线程安全的,比如

List list = Collections.synchronizedList(new ArrayList);

泛型

Java集合的缺点,一旦把一个对象丢进集合里之后,集合就会忘记这个对象的数据类型,当再次取出的时候,编译类型就会变成Object(其运行类型没有改变),当使用的时候,需要做强制类型转换(遍历的时候 要强制转换),这种类型转换会使得代码臃肿,而且容易引发ClassCastException异常(比如把整形误加入了集合,但是在遍历的时候用了String的length方法)。增加了泛型后的集合,可以记住元素的类型,而且在编译的时候检查集合中元素的类型,如果添加不满足要求的对象,编译器会提示错误。

List<String> strList = new ArrayList<String>();//java 7之前 必须这么写
List<String> strList = new ArrayList<>();//java 7以及之后 可以这么写了

Map<String,Integer> = new Hash<>();

事实上,泛型不光可以用于集合,还能用于定义泛型接口、类

public interface List<E>
{
//定义方法的时候 能用E
void add(E x){
}
//还可指定返回值类型
Iterator<E> iterator(){
}

}

所以,可以吧List想象成 E被全部替换成String的特殊List子类接口,等同于下面的类

Public interface ListString extends List{
	void add(String x)
	Iterator<String> iterator();

}

这样就通过只定义一个接口,实际使用可能无数个接口的问题。而且泛型不光能用于集合类。需要指出的是,定义构造器依然使用 public className()的形式而非public className<>()

泛型的其他知识不深入了 用到的时候看李刚

注解Annotation

@Override  强制子类必须覆盖父类方法。主要是帮程序员避免一些低级错误,比如把info方法不小心写成了inf0,如果这样 在编译运行的时候 都不会给出提示,但是结果和预期不一致,这种没有任何错误提示的错误才是最难调试的错误
@Deprecated 标记已经过时,当其他程序使用过时的类 方法时候给出警告提示
@SuppressWarnings 抑制编译器警告
@FunctionalInterface 函数式接口

还有几个修饰其他Annotation的元Annotation,如@Documented用于javadoc生成文档的不展开了 用到看书,以及还可以自定义注解

多线程

作用:如浏览器同时下载多个图片、一个web服务器同时响应多个用户的请求,java虚拟机提供一个超级线程来进行垃圾回收;图形化界面提供一个进程用于收集用户界面事件
线程必须依赖父进程的存在,线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但是不拥有系统资源
线程是独立运行的,并不知道进程中是否有其他线程的存在,其执行时抢占式的。
java创建了一个进程,实际上有两个进程,一个是java主线程,另一个才是你新建的线程
线程的三种创建方式
1、通过继承Thread类,重写run方法。然后新建子类的对象,调用start方法运行.
2、通过实现Runnable接口,重写run方法。然后新建实现的对象,调用start方法运行.
3、Java5新增,使用Callable和Future创建进程,我们想要把任意方法都包装成线程执行体,而不想每次都写run方法,所以可使用call方法

当使用继承创建对象的时候,多个进程无法共享线程类的实例变量。默认情况主线程为Main,用户启动的线程为Thread-x;

线程常用的方法
Thread.currentThread() 静态方法,返回当前正在执行的线程。如果是继承的方法 可以直接用this访问当前线程
getName 实例方法,返回调用改方法的线程的名字

线程状态

新建New-就绪Runable、运行Running、阻塞Bkocked、死亡Dead

当我们使用start方法启动的时候,线程会就绪等待执行。而我们如果直接调用run方法,那么它立刻就会被运行,而且run方法返回之前,其他线程无法并发执行!

当发生以下情况的时候会blocked状态
1、调用sleep
2、调用了阻塞io方法,返回之前该进程会被阻塞
3、尝试获得一个同步监视器,但是这个同步监视器正被其他线程所持有
4、线程在等待某个通知
5、程序调用了suspend方法挂起,但是这个容易导致死锁。当调用了resume方法恢复时候变成就绪
被阻塞的进程将在合适的时候重新变成就绪状态(而非直接执行状态)

join方法可以让一个进程等待另一个进程完成再运行
后台进程 Daemon Thread 又被称为守护进程或者精灵线程。当所有前台进程死亡的时候,后台线程会自动死亡。Jvm的垃圾回收就是典型的后台线程
yield 线程让步,线程暂停一下 进入就绪状态,让其他优先级更高的进程有机会运行

线程有优先级,可通过setPriority方法 和getPriority方法

线程同步和线程通信、线程池 以后再看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值