# 1. 数据类型

boolean flag;
byte a;
short b;
int c;
long d;
float e;
double f;
char g;


# 2. 输入输出

import java.util.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class Main{
public static void main(String args[]){
int sum = 0;
int x;
for(int i = 1;i <= n; ++ i){
sum += x;
}
double d = 1.23456789;
System.out.println("sum=" + sum);
//printf同C语言%md留足m格%m.nf占m列四舍五入保留n位小数
System.out.printf("%5d %.3f\n", sum, num);//注意哪怕指定位数也会四舍五入
System.out.println(String.format("%.2f", d));//指定位数就不会四舍五入
System.out.println(String.format("%f", d));//不指定位数就会自动四舍五入
System.out.println("Hello world");
student std = new student();
std.speak("Hello java");
}
}

class student{
public void speak(String s){
System.out.println(s);
}
}


3 2.345678 1 2 3


sum=6
6 2.346
1.23
1.234568
Hello world
Hello java


# 3. 数组

import java.util.*;
import java.math.*;
import java.text.*;

public class Main{
public static void main(String args[]){
int a[];
a = new int[5];
int b[][];
b = new int [5007][1007];
System.out.println(a.length + " " + b.length);
//int [] a, b[];//表示声明一个一维数组a一个二维数组b
//b[0] = new int [100];
//b[1] = new int [25];
int sum = 0;
for(int i = 1;i <= n; ++ i){
}
for(int i = 1; i <= n; ++ i){
sum += a[i];
}
for(int i : a){//遍历全部
System.out.println(i);
}
//使用println输出char型数组的时候是输出全部元素的值
char ch[] = {'H', 'e', 'l', 'l', 'o'};
System.out.println(ch);
System.out.println("sum = " + sum);

}
}


3 1 2 3


5 5007
0
1
2
3
0
Hello
sum = 6


3 1 2 3


10007 5007
Hello
sum = 6


# 4. 选择语句

import java.util.*;
import java.math.*;
import java.text.*;

public class Main{
public static void main(String args[]){
if(n >= 100){
System.out.printf("Yes\n");
}
else System.out.println("No\n");
switch (n){
case 1:
System.out.println("Yes");
break;
case 100:{
System.out.println("No");
System.out.println("what?");
}
break;
default:
System.out.println("Hello?");
}

}
}



100


Yes
No
what?


# 5. 类

## 5.1 类

import java.util.*;
import java.math.*;
import java.text.*;

class function{
int sum = 0;
static int num;//类变量
return x + y + num;
}
return a[0] + a[1] + num;
}

int sum = 0;
for(int tmp : a){
sum += tmp;
}
return sum + num;
}
static int max(int a, int b){
return a > b ? a : b;
}
}

public class Main{
public static void main(String args[]){
function.num = 23330000;//类变量可以直接访问不用new
Point pos = new Point(1, 2);
System.out.println(pos.Point());
Point pos2 = new Point();
System.out.println(pos2.Point());
System.out.println(pos2);
pos2 = pos;
System.out.println(pos);
System.out.println(pos2);//原来的pos2已经被垃圾回收系统回收了

function fun = new function();

System.out.println(res);

int b[];
b = new int[3];
b[0] = 10;
b[1] = 100;
b[2] = 1000;
System.out.println(ans);
}
}

class A{
int sum;
void f(){
int sum = 10;
System.out.println(sum);
}
}

class Point {
int x, y;
Point (){
x = 0;
y = 0;
}
Point (int a, int b){
x = a;
y = b;
}
int Point (){
return x + y;
}
}


import

//package Main;

import java.util.*;
import java.io.*;
import java.lang.*;

public class Main{
public static void main(String[] args){
Date date = new Date();
System.out.println(date.toString());
}
}


## 5.2 对象数组

import java.util.*;
import java.io.*;
import java.lang.*;

public class Main{
public static void main(String[] args){
Student stu[] = new Student[11];
for(int i = 1; i  <= 10; ++ i){
stu[i] = new Student();
stu[i].number = 100 + i;
}
for(int i = 1; i <= 10; ++ i){
System.out.println(stu[i].number);
}
}
}

class Student {
int number;
}

class tom{
private double weight;
protected double age;
public double hight;

}


java支持类里面定义一个类（内部类）

## 5.3 关键字private，public用处

public class Main {
public static void main(String[] args) {
Person ming = new Person();
ming.setName("Xiao Ming"); // 设置name
ming.setAge(12); // 设置age
System.out.println(ming.getName() + ", " + ming.getAge());
}
}

class Person {
private String name;
private int age;

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return this.age;
}

public void setAge(int age) {
if (age < 0 || age > 100) {
throw new IllegalArgumentException("invalid age value");
}
this.age = age;
}
}



private方法只能由内部方法调用。

## 5.4 可变参数

class Group {
private String[] names;

public void setNames(String... names) {
this.names = names;
}
}


class Group {
private String[] names;

public void setNames(String[] names) {
this.names = names;
}
}


Group g = new Group();
g.setNames(new String[] {"Xiao Ming", "Xiao Hong", "Xiao Jun"}); // 传入1个String[]


Group g = new Group();
g.setNames(null);


## 5.5 参数绑定

public class Main {
public static void main(String[] args) {
Person p = new Person();
String[] fullname = new String[] { "Homer", "Simpson" };
p.setName(fullname); // 传入fullname数组
System.out.println(p.getName()); // "Homer Simpson"
fullname[0] = "Bart"; // fullname数组的第一个元素修改为"Bart"
System.out.println(p.getName()); // "Homer Simpson"还是"Bart Simpson"?
}
}

class Person {
private String[] name;

public String getName() {
return this.name[0] + " " + this.name[1];
}

public void setName(String[] name) {
this.name = name;
}
}



Homer Simpson
Bart Simpson


## 5.6 构造方法

    public Person(String name, int age) {
this.name = name;
this.age = age;
}


class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public Person(String name) {
this.name = name;
this.age = 12;
}

public Person() {
}
}


## 5.7 方法重载

class Hello {
public void hello() {
System.out.println("Hello, world!");
}

public void hello(String name) {
System.out.println("Hello, " + name + "!");
}

public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}


# 6.子类与继承

## 6.1 继承

Java只允许一个class继承自一个类，因此，一个类有且仅有一个父类。只有Object特殊，它没有父类。

1. java中只支持单继承，不支持多继承。（其他语言有的支持多继承，例如C++，格式extends 父类1，父类2，…）
2. 支持多层继承（形成继承体系）。
3. 子类只能继承父类中的非私有成员，但可以通过父类的成员方法调用父类的私有成员变量。
4. 子类不能继承父类的构造方法，但可以通过super关键字访问父类的构造方法。

//package Main;

import java.util.*;
import java.io.*;
import java.lang.*;

public class Main{
public static void main(String[] args){
Student stu1 = new Student();
stu1.showpeople();
}
}

class people {
int age = 10, leg = 2, hand = 2;
protected void showpeople(){
System.out.printf("%d岁，%d只脚，%d只手\n", age, leg, hand);
}
}
class Student extends people {
int number;
return x + y;
}
}



## 6.2 protected关键字

class Person {
private String name;
private int age;
}

class Student extends Person {
public String hello() {
return "Hello, " + name; // 编译错误：无法访问name字段
}
}


## 6.3 instanceof运算符

instanceof主要用来判断一个类是否实现了某个接口，或者判断一个实例对象是否属于一个类。

1.判断一个对象是否属于一个类

boolean result = p instanceof Student;


2.对象类型强制转换前的判断

Person p = new Student();
//判断对象p是否为Student类的实例
if(p instanceof Student)
{
//向下转型
Student s = (Student)p;
}


## 6.4 this 和 super的用法

this

this 是自身的一个对象，代表对象本身，可以理解为：指向对象本身的一个指针。

this 的用法在 Java 中大体可以分为3种：

1. 普通的直接引用

1. 形参与成员名字重名，用 this 来区分：

class Person {
private int age = 10;
public Person(){
System.out.println("初始化年龄："+age);
}
public int GetAge(int age){
this.age = age;
return this.age;
}
}

public class test1 {
public static void main(String[] args) {
Person Harry = new Person();
System.out.println("Harry's age is "+Harry.GetAge(12));
}
}


初始化年龄：10
Harry's age is 12


1. 引用构造函数

super

super 可以理解为是指向自己超（父）类对象的一个指针，而这个超类指的是离自己最近的一个父类。
super 也有三种用法：

1. 普通的直接引用

1. 子类中的成员变量或方法与父类中的成员变量或方法同名

class Country {
String name;
void value() {
name = "China";
}
}

class City extends Country {
String name;
void value() {
name = "Shanghai";
super.value();      //调用父类的方法
System.out.println(name);
System.out.println(super.name);
}

public static void main(String[] args) {
City c=new City();
c.value();
}
}


Shanghai
China


1. 引用构造函数

super(参数)：调用父类中的某一个构造函数（应该为构造函数中的第一条语句）。
this(参数)：调用本类中另一种形式的构造函数（应该为构造函数中的第一条语句）。

class Person {
public static void prt(String s) {
System.out.println(s);
}

Person() {
prt("父类·无参数构造方法： "+"A Person.");
}//构造方法(1)

Person(String name) {
prt("父类·含一个参数的构造方法： "+"A person's name is " + name);
}//构造方法(2)
}

public class Chinese extends Person {
Chinese() {
super(); // 调用父类构造方法（1）
prt("子类·调用父类"无参数构造方法"： "+"A chinese coder.");
}

Chinese(String name) {
super(name);// 调用父类具有相同形参的构造方法（2）
prt("子类·调用父类"含一个参数的构造方法"： "+"his name is " + name);
}

Chinese(String name, int age) {
this(name);// 调用具有相同形参的构造方法（3）
prt("子类：调用子类具有相同形参的构造方法：his age is " + age);
}

public static void main(String[] args) {
Chinese cn = new Chinese();
cn = new Chinese("codersai");
cn = new Chinese("codersai", 18);
}
}


父类·无参数构造方法： A Person.



### 6.4.1 super 和 this的异同

super
super关键字表示父类（超类）。子类引用父类的字段时，可以用super.fieldName。例如：

class Student extends Person {
public String hello() {
return "Hello, " + super.name;
}
}

• super(参数)：调用基类中的某一个构造函数（应该为构造函数中的第一条语句）
• this(参数)：调用本类中另一种形成的构造函数（应该为构造函数中的第一条语句）
• super:　它引用当前对象的直接父类中的成员（用来访问直接父类中被隐藏的父类中成员数据或函数，基类与派生类中有相同成员定义时如：super.变量名 super.成员函数据名（实参） this：它代表当前对象名（在程序中易产生二义性之处，应使用 this 来指明当前对象；如果函数的形参与类中的成员数据同名，这时需用 this 来指明成员变量名）
• 调用super()必须写在子类构造方法的第一行，否则编译不通过。每个子类构造方法的第一条语句，都是隐含地调用 super()，如果父类没有这种形式的构造函数，那么在编译的时候就会报错。
super() 和 this() 类似,区别是，super() 从子类中调用父类的构造方法，this() 在同一类内调用其它方法。
• super() 和 this() 均需放在构造方法内第一行。
• 尽管可以用this调用一个构造器，但却不能调用两个。
• this 和 super 不能同时出现在一个构造函数里面，因为this必然会调用其它的构造函数，其它的构造函数必然也会有 super 语句的存在，所以在同一个构造函数里面有相同的语句，就失去了语句的意义，编译器也不会通过。
• this() 和 super() 都指的是对象，所以，均不可以在 static 环境中使用。包括：static 变量,static 方法，static 语句块。
• 从本质上讲，this 是一个指向本对象的指针, 然而 super 是一个 Java 关键字。

class Student extends Person {
protected int score;

public Student(String name, int age, int score) {
super(); // 自动调用父类的构造方法
this.score = score;
}
}


class Student extends Person {
protected int score;

public Student(String name, int age, int score) {
super(name, age); // 调用父类的构造方法Person(String, int)
this.score = score;
}
}


• 继承是面向对象编程的一种强大的代码复用方式；
• Java只允许单继承，所有类最终的根类是Object；
• protected允许子类访问父类的字段和方法；
• 子类的构造方法可以通过super()调用父类的构造方法；
• 可以安全地向上转型为更抽象的类型；
• 可以强制向下转型，最好借助instanceof判断；
• 子类和父类的关系是is，has关系不能用继承。

## 6.5 final关键字

final类不能被继承，也就是说不能拥有子类
final方法不允许被子类重写。
final +成员变量 = 常量

## 6.6 继承与多态

Java的实例方法调用是基于运行时的实际类型的动态调用，而非变量的声明类型。

package income;

public class come {
public static void main(String[] args) {
// 给一个有普通收入,工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}

public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
}
}

class Income {
protected double income;

public Income(double income) {
this.income = income;
}

public double getTax() {
return income * 0.1; // 税率10%
}
}

class Salary extends Income {
public Salary(double income) {
super(income);
}

@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}

class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}

@Override
public double getTax() {
return 0;
}
}



## 6.7 覆写Object方法

toString()：把instance输出为String；
equals()：判断两个instance是否逻辑相等；
hashCode()：计算一个instance的哈希值。

final

class Person {
public final String name;
public Person(String name) {
this.name = name;
}
}


## 6.7 abstract 类和 abstract 方法 (抽象类与抽象方法)

abstract class Person {
public abstract void run();
}


Person p = new Person(); // 编译错误


• 上层代码只定义规范（例如：abstract class Person）；
• 不需要子类就可以实现业务逻辑（正常编译）；
• 具体的业务逻辑由不同的子类实现，调用者并不关心。

1. abstract类中可以有abstract方法

abstract类中可以有abstract方法，也可以有非abstract方法

1. abstract类不能使用new运算符创建对象

1. abstract类的子类

abstract class GirlFriend{
//抽象类，封装了两个行为标准
abstract void speak();
abstract void cooking();
}

class ChinaGirlFriend extends GirlFriend{
void speak(){
System.out.println("你好");
}
void cooking(){
System.out.println("水煮鱼");
}
}

class AmercanGirlFriend extends GirlFriend{
void speak(){
System.out.println("hello");
}
void cooking(){
System.out.println("roast beef");
}
}

class boy{
GirlFriend friend；
void setGirlFriend(GirlFriend f){
friend=f；
}
void showGirlFriend(){
friend.speaking();
friend.cooking();
}
}
public class text{
public static void main(String args[]){
GirlFriend girl =new ChineseGirlFriend();      //这里girl是上转型对象
Boy boy=new boy();
boy.setGirlFriend(girl);
boy.showGirlFriend();
girl=new AmericanGirlFriend();             //girl 是上转型对象
boy.setGirlFriend(girl);
boy.showGirlFriend();
}
}


• 通过abstract定义的方法是抽象方法，它只有定义，没有实现。抽象方法定义了子类必须实现的接口规范；
• 定义了抽象方法的class必须被定义为抽象类，从抽象类继承的子类必须实现抽象方法；
• 如果不实现抽象方法，则该子类仍是一个抽象类；
• 面向抽象编程使得调用者只关心抽象方法的定义，不关心子类的具体实现。

# 7. 接口与实现

## 7.1 接口的作用？

abstract class Person {
public abstract void run();
public abstract String getName();
}


interface Person {
void run();
String getName();
}


class Student implements Person, Hello { // 实现了两个interface
...
}


interface Hello {
void hello();
}

interface Person extends Hello {
void run();
String getName();
}


default方法

default方法和抽象类的普通方法是有所不同的。因为interface没有字段，default方法无法访问字段，而抽象类的普通方法可以访问实例字段。

1. 有利于代码的规范

2. 有利于代码进行维护

3. 有利于代码的安全和严密

4. 丰富了继承的方式

## 7.3 接口的相关语法

​ 关键字：interface public interface 接口名 {}

1. 常量（没有变量） ( public static final ) int MAX = 100; 可以省略public static final

2. 抽象方法 (public abstract) void add(); 可以省略public abstract

​ 常量和抽象方法都只有一种访问修饰符：public

​ 接口默认提供 public，static，final，abstract 关键字

1. 类可以实现一个或多个接口 public class Dog implements Eatable,Sleepable

​ Dog 也可以继承一个具体类 public class Dog extends Animal implements Eatable , Sleepable

1. 类中必须重写接口中的全部方法（ 抽象类 可只重写接口中的部分方法）

2. 类中重写的方法，访问修饰符必须是 public

3. 接口中定义的常量，在继承了接口的类中可以直接使用。

## 7.3 接口间的继承

/*
public interface A{}

public interface B extends A{}    // 接口B继承的A
*/
public interface Eatable{     //定义了一个Eatable接口
void eat();
}

public interface Sleepable{    //定义了一个Sleepable接口
void sleep();
}

public class Animal{          // 定义了一个Animal类
public String name;
public Animal(String name) {
this.name = name;
}
}

public Dog extends Animal implements Eatable,Sleepable{    //继承了Animal类，Eatable接口 ，Sleepable方法
public Dog(String n) {
this(n);
}
public void eat() {         //重写Eatable中的eat方法
System.out.println(name+"吃骨头");
}
public void sleep() {       //重写Sleepable中的sleep方法
System.out.println(name+"睡得很好");
}
}


## 7.4 接口的回调（类似于 对象的上转型对象 ）

​ 该 接口对象 可以调用 被类实现了的 接口方法

public interface Com{}

public class Object implements Com{}

Com com = new Object();   //接口的回调


## 7.8 abstract类和接口类的比较

1.abstract类和接口都可以有abstract方法。
2.接口中只可以有常量，不能有变量；而abstract类中既可以有常量又可以有变量。
3.abstract类中也可以由非abstract方法，接口不可以。

• Java的接口（interface）定义了纯抽象规范，一个类可以实现多个接口；
• 接口也是数据类型，适用于向上转型和向下转型；
• 接口的所有方法都是抽象方法，接口不能定义实例字段；
• 接口可以定义default方法

# 8. 异常

Java规定：

## 8.1 捕获异常

public class Main {
public static void main(String[] args) {
byte[] bs = toGBK("中文");
System.out.println(Arrays.toString(bs));
}

static byte[] toGBK(String s) {
try {
// 用指定编码转换String为byte[]:
return s.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
// 如果系统不支持GBK编码，会捕获到UnsupportedEncodingException:
System.out.println(e); // 打印异常信息
return s.getBytes(); // 尝试使用用默认编码
}
}
}



toGBK()方法中，因为调用了String.getBytes(String)方法，就必须捕获UnsupportedEncodingException。我们也可以不捕获它，而是在方法定义处用throws表示toGBK()方法可能会抛出UnsupportedEncodingException，就可以让toGBK()方法通过编译器检查，我们在main()方法中捕获异常并处理

public class Main {
public static void main(String[] args) {
try {
byte[] bs = toGBK("中文");
System.out.println(Arrays.toString(bs));
} catch (UnsupportedEncodingException e) {
System.out.println(e);
}
}

static byte[] toGBK(String s) throws UnsupportedEncodingException {
// 用指定编码转换String为byte[]:
return s.getBytes("GBK");
}
}



• Java使用异常来表示错误，并通过try … catch捕获异常；
• Java的异常是class，并且从Throwable继承；
• Error是无需捕获的严重错误，Exception是应该捕获的可处理的错误；
• RuntimeException无需强制捕获，非RuntimeException（Checked - Exception）需强制捕获，或者用throws声明；
• 不推荐捕获了异常但不进行任何处理。

public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException e) {
System.out.println("IO error");
} catch (UnsupportedEncodingException e) { // 永远捕获不到
}
}


public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (UnsupportedEncodingException e) {
} catch (IOException e) {
System.out.println("IO error");
}
}


Java的try ... catch机制还提供了finally语句，finally语句块保证有无错误都会执行。上述代码可以改写如下：

public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (UnsupportedEncodingException e) {
} catch (IOException e) {
System.out.println("IO error");
} finally {
System.out.println("END");
}
}


1. finally语句不是必须的，可写可不写；
2. finally总是最后执行。

public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException | NumberFormatException e) { // IOException或NumberFormatException
} catch (Exception e) {
System.out.println("Unknown error");
}
}


• 多个catch语句的匹配顺序非常重要，子类必须放在前面；
• finally语句保证了有无异常都会执行，它是可选的；
• 一个catch语句也可以匹配多个非继承关系的异常。

## 8.2 抛出异常

public class Main {
public static void main(String[] args) {
try {
process1();
} catch (Exception e) {
e.printStackTrace();
}
}

static void process1() {
process2();
}

static void process2() {
Integer.parseInt(null); // 会抛出NumberFormatException
}
}



java.lang.NumberFormatException: null
at java.base/java.lang.Integer.parseInt(Integer.java:614)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at Main.process2(Main.java:16)
at Main.process1(Main.java:12)
at Main.main(Main.java:5)


printStackTrace()对于调试错误非常有用，上述信息表示：NumberFormatException是在java.lang.Integer.parseInt方法中被抛出的，从下往上看，调用层次依次是：

1. main()调用process1()
2. process1()调用process2()
3. process2()调用Integer.parseInt(String)
4. Integer.parseInt(String)调用Integer.parseInt(String, int)

1. 创建某个Exception的实例；
2. throw语句抛出。

void process2(String s) {
if (s==null) {
NullPointerException e = new NullPointerException();
throw e;
}
}


• 调用printStackTrace()可以打印异常的传播栈，对于调试非常有用；

• 捕获异常并再次抛出新的异常时，应该持有原始异常信息；

• 通常不要在finally中抛出异常。如果在finally中抛出异常，应该原始异常加入到原有异常中。调用方可通过Throwable.getSuppressed()获取所有添加的Suppressed Exception

# 9. 反射

## 9.1 Class类

class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时，将其加载进内存。

public final class Class {
private Class() {}
}


String类为例，当JVM加载String类时，它首先读取String.class文件到内存，然后，为String类创建一个Class实例并关联起来：

Class cls = new Class(String);


Class cls = String.class;


String s = "Hello";
Class cls = s.getClass();


Class cls = Class.forName("java.lang.String");


Class cls1 = String.class;

String s = "Hello";
Class cls2 = s.getClass();

boolean sameClass = cls1 == cls2; // true


• JVM为每个加载的classinterface创建了对应的Class实例来保存classinterface的所有信息；

• 获取一个class对应的Class实例后，就可以获取该class的所有信息；

• 通过Class实例获取class信息的方法称为反射（Reflection）；

• JVM总是动态加载class，可以在运行期根据条件来控制加载class。

# 11. 多线程

Java多线程编程的特点又在于：

## 11.1 线程概述

3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是，线程只能从就绪状态进入到运行状态。
4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权，暂时停止运行。直到线程进入就绪状态，才有机会转到运行状态。阻塞的情况分三种：
(01) 等待阻塞 – 通过调用线程的wait()方法，让线程等待某工作的完成。
(02) 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用)，它会进入同步阻塞状态。
(03) 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时，线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时，线程重新转入就绪状态。

Runnable 是一个接口，该接口中只包含了一个run()方法。它的定义如下：

public interface Runnable {
public abstract void run();
}


public class Thread implements Runnable {}


import java.util.*;

public class Main {
public static void main(String[] args) {

//ts1.setName("张三")；
//ts2.setName("里斯");
//ts3.setName("王五");

ts1.start();
ts2.start();
ts3.start();
}
}

{
private int ticket = 10;
public void run() {
//System.out.println(getName() + ":" + x + ",日期:" + new Date());
//睡眠
//休息1秒钟
//try {
///}catch(InterruptedExecption e) {
//	e.printStackTrace();
//}
for(int i = 0; i < 20; ++ i) {
if(this.ticket > 0) {
System.out.println(this.getName() + "买票:ticket" + this.ticket  -- );
}
}
}
}


Thread-0 卖票：ticket10


### 11.1.2 Runnable的多线程示例

import java.util.*;

public class Main {
public static void main(String[] args) {

ts1.start();
ts2.start();
ts3.start();
}
}

{
private int ticket = 10;
public void run() {
for(int i = 0; i < 20; ++ i) {
if(this.ticket > 0) {
}
}
}
}


Thread-0买票:ticket10


### 11.1.3 start() 和 run()的区别

start() : 它的作用是启动一个新线程，新线程会执行相应的run()方法。start()不能被重复调用。
run() : run()就和普通的成员方法一样，可以被重复调用。单独调用run()的话，会在当前线程中执行run()，而并不会启动新线程！


super(name);
}

public void run(){
}
};

public class Demo {
public static void main(String[] args) {

}
}


main call mythread.run()
main is running


## 创建线程

Java语言内置了多线程支持。当Java程序启动的时候，实际上是启动了一个JVM进程，然后，JVM启动主线程来执行main()方法。在main()方法中，我们又可以启动其他线程。

public class Main {
public static void main(String[] args) {
t.start(); // 启动新线程
}
}

@Override
public void run() {
}
}



public class Main {
public static void main(String[] args) {
t.start(); // 启动新线程
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
}
}



## 线程的优先级

Thread.setPriority(int n) // 1~10, 默认值5


Java用Thread对象表示一个线程，通过调用start()启动一个新线程；

Thread.sleep()可以把当前线程暂停一段时间。

## 线程的状态

• New：新创建的线程，尚未执行；
• Runnable：运行中的线程，正在执行run()方法的Java代码；
• Blocked：运行中的线程，因为某些操作被阻塞而挂起；
• Waiting：运行中的线程，因为某些操作在等待中；
• Timed Waiting：运行中的线程，因为执行sleep()方法正在计时等待；
• Terminated：线程已终止，因为run()方法执行完毕。

• 线程正常终止：run()方法执行到return语句返回；
• 线程意外终止：run()方法因为未捕获的异常导致线程终止；
• 对某个线程的Thread实例调用stop()方法强制终止（强烈不推荐使用）。

Java线程对象Thread的状态包括：NewRunnableBlockedWaitingTimed WaitingTerminated

## 中断线程

public class Main {
public static void main(String[] args) throws InterruptedException {
t.start();
t.interrupt(); // 中断t线程
t.join(); // 等待t线程结束
System.out.println("end");
}
}

public void run() {
int n = 0;
while (! isInterrupted()) {
n ++;
System.out.println(n + " hello!");
}
}
}



public class Main {
public static void main(String[] args)  throws InterruptedException {
t.start();
t.running = false; // 标志位置为false
}
}

public volatile boolean running = true;
public void run() {
int n = 0;
while (running) {
n ++;
System.out.println(n + " hello!");
}
System.out.println("end!");
}
}



volatile关键字解决的是可见性问题：当一个线程修改了某个共享变量的值，其他线程能够立刻看到修改后的值。

volatile关键字解决了共享变量在线程间的可见性问题。

## 守护线程

Thread t = new MyThread();
t.setDaemon(true);
t.start();


## 线程同步

Java程序使用synchronized关键字对一个对象进行加锁：

synchronized(lock) {
n = n + 1;
}


synchronized保证了代码块在任意时刻最多只有一个线程能执行。

• 我们来概括一下如何使用synchronized

1. 找出修改共享变量的线程代码块；
2. 选择一个共享实例作为锁；
3. 使用synchronized(lockObject) { ... }

在使用synchronized的时候，不必担心抛出异常。因为无论是否有异常，都会在synchronized结束处正确释放锁：

public void add(int m) {
synchronized (obj) {
if (m < 0) {
throw new RuntimeException();
}
this.value += m;
} // 无论有无异常，都会在此释放锁
}


JVM规范定义了几种原子操作：

• 基本类型（longdouble除外）赋值，例如：int n = m
• 引用类型赋值，例如：List<String> list = anotherList

## 同步方法

public void add(int n) {
synchronized(this) { // 锁住this
count += n;
} // 解锁
}

public synchronized void add(int n) { // 锁住this
count += n;
} // 解锁


03-22

10-31
01-23 1万+
11-06 3万+
03-31 1万+
06-16 6万+
03-02
05-04 6748
05-13 92