Java 总结归纳
部分定义:
标识符:
定义: Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符
技巧:凡是自己可以起名字的地方都叫标识符。
变量的一些知识点:
-
变量可以说内存中的一个存储区域,也叫做程序中最基本的存储单元
-
这个区域的数据可以在某一些范围内不断的变化。这就要涉及到一些变量类型的东西,不同的数据类型 数值的范围不用
-
注意的点:
Java中每个变量必须先声明,后使用
变量的作用域: 其定义所在的 {} 内
变量的分类-按声明的位置的不同
在方法体外,类体内声明的变量称为成员变量。
在方法体内部声明的变量称为局部变量。
注意: 局部变量除了形参外,需要显示初始化。
也就是说当局部变量在方法体或者代码块中 需要初始化。
自动类型转换:
当把任何基本数据类型的值和String 进行高连接运算时,基本数据类型将自动转化为String类型
例子:
三元运算符:
关于Math 的知识点:
Math.floor() 表示向下取整,返回double类型 (floor—地板)
Math.ceil() 表示向上取整,返回double类型 (ceil—天花板)
Math.round() 四舍五入,返回int类型
Math.cos为计算弧度的余弦值
Math.toRadians函数讲角度转换为弧度
值传递机制:
Java Bean:
方法重写:
this 和super 的区别:
多态性的理解:
一句话理解就是:
多态性的一些特点:
instaance of 操作符
static 关键字:
修饰属性、方法、代码块、内部类
抽象类和抽象方法:
接口的部分知识点:
内部类:
成员内部类:
局部内部类:
声明在方法体内或者 代码块中:
如何使用:
- 只能声明在它的方法或者代码块中,先声明后使用。
- 但是它的对下昂可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或者父类的接口类型。
线程:
-
多线程的创建: 方式一: 继承于Thread类
-
1 创建一个继承于Thread类的子类
-
2 重写Thread类的run() --> 将此线程执行官的操作声明在run()中
-
3 创建Thread类的子类的对象
-
4 通过此对象调用start(): 作用一:启动当前线程 作用二: 调用当前线程的run()
-
创建多线程的方式二: 实现Runnable 接口
-
1 创建一个实现了Runnable 接口的类
-
2 实现类去实现Runnable中的抽象方法Run
-
3 创建实现类的对象
-
4 将此对象作为参数传递带Thread 类的构造器中,创建Thread类的对象
-
5 通过Thread类的对象调用start()
-
比较创建线程的两种方法:
-
开发中优先选择: 实现Runnable接口的方式
-
原因: 1 实现的方式没有类的单继承性的局限性
-
2 实现的方式 更适合处理多线程有共享数据的情况
相同点: 都需要重写run(),都是将线程要执行的逻辑声明在run()中。
*
说明两个问题
问题一: 我们启动一个线程,必须点用start() 方法。不能调run()的方式启动线程
问题二:如果再启动一个,就必须重现创建thread子类的对象,调用该对象的start()方法
-
测试Thread 中常用的方法:
-
1 start():启动当前线程;调用当前线程的run()、
-
2 run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
-
3 currentThread(): 静态方法, 返回执行当前代码的线程
-
4 getName(): 获取当先线程的名字
-
5 setName(): 设置当前线程的名字
-
6 yield(): 释放当先cpu的执行权
-
7 join(): 在线程A 中调用线程B 的 join(),此时线程A 就进 * 入阻塞状态,知道线程B 执行完成以后,
-
线程A 才结束阻塞状态
-
8 stop(): 已过时 在执行此方法时,强制结束当前线程
-
9 sleep():
-
10 isAlive(): 判断是否存活
-
线程的优先级
-
1
-
MAX_PRIORITY : 10
-
MIN_PRIORITY: 1
-
NORM_PRIORITY: 5
-
2 如何获取和设置当前线程的优先级
-
getPriority():获取线程的优先级
-
setPriority(): 设置线程的优先级
-
说明: 高优先级的线程要抢占cpu的优先级,但是只是从概率上来说
-
高优先级的线程高概率的情况下被执行。并不意味着只有高优先级的线程执行完以后,低优先级才执行
线程的通信: wait()/ notify() / notifyAll()
线程的生命周期
Java中通过同步机制解决线程的安全问题:
方式一:
同步代码块:
synchronized 关键字
synchronized(同步监视器){
//需要被同步的代码
}
说明: 1. 操作共享数据的代码,即为需要被同步的代码
2. 共享数据: 多个线程共同操作的变量。
3. 同步监视器,俗称: 锁。 任何一个类的对象都可以
充当锁。
要求: 多个线程必须共用同一把锁。
继承中的实现synchronized
class Window extends Thread{
private static int ticket = 100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (this){//synchronized(obj){
if (ticket > 0) {
System.out.println(getName() + ": 票号为: " + ticket );
ticket--;
}else {
break;
}
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("窗口1: ");
window2.setName("窗口2: ");
window3.setName("窗口3: ");
window1.start();
window2.start();
window3.start();
}
}
接口Runnable实现synchronzed
class Window1 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 票号为: " + ticket );
ticket--;
}else {
break;
}
}
}
}
}
public class WindowTest1 {
public static void main(String[] args) {
Window1 window = new Window1();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("Window 1");
t2.setName("Window 2");
t3.setName("Window 3");
t1.start();
t2.start();
t3.start();
}
}
方式二:
同步方法:
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明为同步的。
继承中的实现synchronized
/**
* 同步方法仍然涉及到了同步监视器,只是不需要我们显示声明
*
* 注意: 非静态的同步方法,同步监视器是:this
* 静态的同步方法,同步监视器是: 当前类本省
*
*/
class Window3 extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
show();
}
}
private static synchronized void show(){//同步监视器是 当前类本身 window3.class
// private synchronized void show(){//同步监视器: t1,t2,t3 此方法不能实现同一个锁,所以要用static
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ": 票号为: " + ticket);
ticket--;
}
}
}
public class WindowTest3 {
public static void main(String[] args) {
Window3 window1 = new Window3();
Window3 window2 = new Window3();
Window3 window3 = new Window3();
window1.setName("窗口1: ");
window2.setName("窗口2: ");
window3.setName("窗口3: ");
window1.start();
window2.start();
window3.start();
}
}
接口Runnable实现synchronzed
class Window2 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
public synchronized void show() { // 同步监视器: this
if (ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 票号为: " + ticket);
ticket--;
}
}
}
public class WindowTest2 {
public static void main(String[] args) {
Window2 window = new Window2();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("Window 1");
t2.setName("Window 2");
t3.setName("Window 3");
t1.start();
t2.start();
t3.start();
}
}
- 同步的方式,解决了线程的安全问题 – 好处
操作同步代码是,只能有一个线程参与,其它线程等待。相当于是一个但线程的操作。
使用同步机制将单例模式中的懒汉式改写为线程安全的
public class BankTest {
}
class Bank{
private Bank(){}
private static Bank instance = null;
public static Bank getInstance(){
//方式一: 效率稍差
// synchronized (Bank.class) {
if (instance == null) {
instance = new Bank();
}
return instance;
}
//方式二: 稍微优化了一下代码,如何第一个进来的已经new 了对象,则后面的就不用再进入同步代码块内部了
if (instance == null) {
synchronized (Bank.class) {
if (instance == null) {
instance = new Bank();
}
}
}
return instance;
}
}
线程的死锁问题:
解决线程的安全问题:Lock
package java1;
import java.util.concurrent.locks.ReentrantLock;
/**
* 解决线程安全的方式三: Lock锁
*
*
*/
class Window implements Runnable{
private int ticket = 100;
//实例化ReentrantLock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try{
//调用锁定Lock()的方法
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 票号为:" + ticket);
ticket--;
}else {
break;
}
}finally {
//调用解锁方法
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
Window window = new Window();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("Window 1");
t2.setName("Window 2");
t3.setName("Window 3");
t1.start();
t2.start();
t3.start();
}
}
知识点: synchronized 与 Lock 异同
同: 解决线程的安全问题
不同点:Lock 有点像手动锁定和解锁,较为灵活
synchronized 机制属于自动的锁定和解锁,在执行完相应的
同步代码块以后,自动的释放同步监视器
线程同步的应用:
package Account;
/**
* 用线程的安全性 去解决现实中的小问题
*/
class Account{
private double balance;
public Account(double balance){
this.balance = balance;
}
//存钱
public synchronized void deposit(double amt){
if (amt > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance +=amt;
System.out.println(Thread.currentThread().getName() + "存钱:" + amt + " 余额:" + balance);
}
}
}
class Customer extends Thread{
private Account acct;
public Customer(Account acct){
this.acct = acct;
}
@Override
public void run(){
for (int i = 0; i < 3; i++) {
acct.deposit(1000);
}
}
}
public class AccountTest {
public static void main(String[] args) {
Account account = new Account(0);
Customer customer1 = new Customer(account);
Customer customer2 = new Customer(account);
customer1.setName("甲");
customer2.setName("乙");
customer1.start();
customer2.start();
}
}
wait() notify() notifyAll() 三个方法的特性:
package ThreadCommunication;
/**
* 线程的通信
* 两个线程打印1-100。线程1和线程2交替打印
*
* 涉及到的三个方法:
* wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
* notify(): 一旦执行此方法,就会唤醒被wait()的一个线程,如果多个线程wait,则按照优先级高的被唤醒
* notifyAll(): 一旦执行此方法,就会唤醒所有的wait线程
*
* 说明:
*
* 1 wait(),notify(),notifyAll三个方法必须使用在同步代码块或同步方法中
* 2 wait(),notify(),notifyAll 三个方法的调用者必须是同步代码块或同步方法中的同步监视器
* 3 wait(),notify(),notifyAll 三个方法 是定义在java.lang.Object类中的
*/
class Number implements Runnable{
private int number = 1;
@Override
public void run() {
while (true){
//wait()和notify()方法的调用必须具有内置锁 synchronized(this) 的代码块内或同步方法才能调用,否则就会报该错误。
synchronized (this) {
notify();
if (number<=100) {
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
try {
//使得该线程阻塞
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
public class CommunicationTest {
public static void main(String[] args) {
Number number = new Number();
Thread t1 = new Thread(number);
Thread t2 = new Thread(number);
t1.setName("线程1: ");
t2.setName("线程2: ");
t1.start();
t2.start();
}
}
例题:sleep() 和 wait() 的异同
相同点: 都可以使当前的线程进入阻塞状态
不同点:
- 两个方法声明的位置不同,Thread类中声明sleep(), Object类中声明wait().
- 调用的要求不同,sleep() 可以在任何需要的场景下调用,wait() 必须是在同步代码或同步方法中。
- 关于释放释放同步监视器,如果两个方法都使用在了同步代码块或同步方法中,sleep() 不会释放同步监视器,wait()会释放同步监视器。
创建线程的方式三: Callable接口
package ThreadNew;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 创建线程的方式三: 实现callable接口。
* 特点:
* 1 Call方法有返回值
* 2 能抛出异常
* 3 支持泛性
*/
//1 创建一个实现Callable的实现类
class NumberThread implements Callable{
// 2 实现call方法,将此线程需要执行的操作声明在call方法中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class CallableUsing {
public static void main(String[] args) {
// 3 创建Callable 接口实现类的对象
NumberThread numberThread = new NumberThread();
// 4 将此callable 接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
FutureTask futureTask = new FutureTask(numberThread);
// 5 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start方法
new Thread(futureTask).start();
try {
// 6 获取Callable中call方法的返回值
//get 方法的返回值即为FutureTask构造器Callable实现类重写的call()的返回值
Object sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
实现线程的方式四: 使用线程池
package ThreadNew;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
* 实现线程的方法四:线程池
*
*/
class NumberThread1 implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100 ; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
}
public class ThreadPool {
public static void main(String[] args) {
// 1 提供指定线程数量的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 2 执行指定线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
executorService.execute(new NumberThread1()); //适用于Runnable
// executorService.submit(); //适用于Callable
//关闭线程池
executorService.shutdown();
}
}