Java的异常和线程
异常
异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。异常机制其实是帮助我们找到程序中的问题,异常的根类是 java.lang.Throwable ,其下有两个子类java.lang.Error 与 java.lang.Exception ,平常所说的异常指 java.lang.Exception 。
Throwable体系: Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。 Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。
Throwable中的常用方法: public void printStackTrace() :打印异常的详细信息。包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。 public String getMessage() :获取发生异常的原因。提示给用户的时候,就提示错误原因。 public String toString() :获取异常的类型和异常描述信息(不用)。
public class DemoException {
public static void main(String[] args) {
int[] arr = new int[1024*1024];
System.out.println("后续代码");
}
}
抛出异常throw
*
throw关键字
作用:
可以使用throw关键字在指定的方法中抛出指定的异常
使用格式:
throw new xxxException("异常产生的原因");
注意:
1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者Exception的子类对象
3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后边创建的是RuntimeException或者是 RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch
*/
public class DemoThrow {
public static void main(String[] args) {
int[] arr = new int[3];
int e = getElement(arr,3);
System.out.println(e);
}
public static int getElement(int[] arr,int index){
if(arr == null){
throw new NullPointerException("传递的数组的值是null");
}
if(index<0 || index>arr.length-1){
throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的使用范围");
}
int ele = arr[index];
return ele;
}
}
Object抛出异常
import java.util.Objects;
public class DemoObjects {
public static void main(String[] args) {
method(null);
}
public static void method(Object obj){
Objects.requireNonNull(obj,"传递的对象的值是null");
}
}
声明异常throws
import java.io.FileNotFoundException;
import java.io.IOException;
public class DemoThrows {
public static void main(String[] args) throws Exception {
readFile("c:\\a.tx");
System.out.println("后续代码");
}
public static void readFile(String fileName) throws FileNotFoundException,IOException{
if(!fileName.equals("c:\\a.txt")){
throw new FileNotFoundException("传递的文件路径不是c:\\a.txt");
}
if(!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名不对");
}
System.out.println("路径没有问题,读取文件");
}
}
异常捕获try…catch
import java.io.IOException;
public class DemoTryCatch {
public static void main(String[] args) {
try{
readFile("d:\\a.tx");
System.out.println("资源释放");
}catch (IOException e){
e.printStackTrace();
}
System.out.println("后续代码");
}
public static void readFile(String fileName) throws IOException {
if(!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名不对");
}
System.out.println("路径没有问题,读取文件");
}
}
代码块 finally
public class Demo02TryCatchFinally {
public static void main(String[] args) {
try {
readFile("c:\\a.tx");
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("资源释放");
}
}
public static void readFile(String fileName) throws IOException {
if(!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名不对");
}
System.out.println("路径没有问题,读取文件");
}
}
类中异常
public class Fu {
public void show01() throws NullPointerException,ClassCastException{}
public void show02() throws IndexOutOfBoundsException{}
public void show03() throws IndexOutOfBoundsException{}
public void show04() throws Exception {}
}
class Zi extends Fu{
public void show01() throws NullPointerException,ClassCastException{}
public void show02() throws ArrayIndexOutOfBoundsException{}
public void show03() {}
public void show04() {
try {
throw new Exception("编译期异常");
} catch (Exception e) {
e.printStackTrace();
}
}
}
多线程
并发与并行 并发:指两个或多个事件在同一个时间段内发生。 并行:指两个或多个事件在同一时刻发生(同时发生)
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
Thread创建线程类
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println("run:"+i);
}
}
}
public class DemoThread {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main:"+i);
}
}
}
Ruable创建线程类
public class RunnableImpl implements Runnable{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
public class RunnableImpl2 implements Runnable{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println("HelloWorld"+i);
}
}
}
public class DemoRunnable {
public static void main(String[] args) {
RunnableImpl run = new RunnableImpl();
Thread t = new Thread(new RunnableImpl2());
t.start();
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
线程中常用的方法
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class DemoGetThreadName {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
new MyThread().start();
new MyThread().start();
System.out.println(Thread.currentThread().getName());
}
}
public class MyThread extends Thread{
public MyThread(){}
public MyThread(String name){
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class DemoSetThreadName {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.setName("小强");
mt.start();
new MyThread("旺财").start();
}
}
public class DemoSleep {
public static void main(String[] args) {
for (int i = 1; i <=60 ; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
匿名内部创建线程
public class DemoInnerClassThread {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"黑马");
}
}
}.start();
Runnable r = new Runnable(){
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"程序员");
}
}
};
new Thread(r).start();
new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"传智播客");
}
}
}).start();
}
}
线程安全-同步代码块
public class RunnableImpl implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while(true){
synchronized (obj){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket--;
}
}
}
}
}
public class DemoTicket {
public static void main(String[] args) {
RunnableImpl run = new RunnableImpl();
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t0.start();
t1.start();
t2.start();
}
}
线程安全 - 同步方法
public class RunnableImpl implements Runnable{
private static int ticket = 100;
@Override
public void run() {
System.out.println("this:"+this);
while(true){
payTicketStatic();
}
}
public static void payTicketStatic(){
synchronized (RunnableImpl.class){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket--;
}
}
}
public void payTicket(){
synchronized (this){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket--;
}
}
}
}
public class DemoTicket {
public static void main(String[] args) {
RunnableImpl run = new RunnableImpl();
System.out.println("run:"+run);
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t0.start();
t1.start();
t2.start();
}
}
Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了,如下: public void lock() :加同步锁。 public void unlock() :释放同步锁
public class RunnableImpl implements Runnable{
private int ticket = 100;
Lock l = new ReentrantLock();
@Override
public void run() {
while(true){
l.lock();
if(ticket>0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
l.unlock();
}
}
}
}
public class DemoTicket {
public static void main(String[] args) {
RunnableImpl run = new RunnableImpl();
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t0.start();
t1.start();
t2.start();
}
}
线程之间的通信
public class DemoWaitAndNotify {
public static void main(String[] args) {
Object obj = new Object();
new Thread(){
@Override
public void run() {
while(true){
synchronized (obj){
System.out.println("告知老板要的包子的种类和数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子已经做好了,开吃!");
System.out.println("---------------------------------------");
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj){
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");
obj.notify();
}
}
}
}.start();
}
}
public class DemoWaitAndNotify {
public static void main(String[] args) {
Object obj = new Object();
new Thread(){
@Override
public void run() {
while(true){
synchronized (obj){
System.out.println("顾客1告知老板要的包子的种类和数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子已经做好了,顾客1开吃!");
System.out.println("---------------------------------------");
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while(true){
synchronized (obj){
System.out.println("顾客2告知老板要的包子的种类和数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子已经做好了,顾客2开吃!");
System.out.println("---------------------------------------");
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj){
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");
obj.notifyAll();
}
}
}
}.start();
}
}
线程池
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建了一个新的线程执行");
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DemoThreadPool {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.shutdown();
es.submit(new RunnableImpl());
}
}
Lambda表达式
Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
1.使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使Lambda。 2. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
Lambda的使用
public class DemoLambda {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 新线程创建了");
}
}).start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" 新线程创建了");
}
).start();
new Thread(()->System.out.println(Thread.currentThread().getName()+" 新线程创建了")).start();
}
}
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 新线程创建了");
}
}
Lambda且无参数、无返回值
public interface Cook {
public abstract void makeFood();
}
public class DemoCook {
public static void main(String[] args) {
invokeCook(new Cook() {
@Override
public void makeFood() {
System.out.println("吃饭了");
}
});
invokeCook(()->{
System.out.println("吃饭了");
});
invokeCook(()-> System.out.println("吃饭了"));
}
public static void invokeCook(Cook cook){
cook.makeFood();
}
}
Lambda有参数,有返回值
import java.util.Arrays;
public class DemoArrays {
public static void main(String[] args) {
Person[] arr = {
new Person("张三",38),
new Person("李四",18),
new Person("王二",19)
};
Arrays.sort(arr,(Person o1, Person o2)->{
return o1.getAge()-o2.getAge();
});
Arrays.sort(arr,(o1, o2)->o1.getAge()-o2.getAge());
for (Person p : arr) {
System.out.println(p);
}
}
}
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
|