异常,多线程,自定义注解

1.定义

异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。
2.异常的分类

从程序执行过程可分为两类

编译时异常:执行javac.exe命名时,可能出现的异常;
是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
运行时异常:执行java.exe命名时,出现的异常。
是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
2.1运行时异常举例

//ArithmeticException
public void test6(){
int a = 10;
int b = 0;
System.out.println(a / b);
}

//InputMismatchException

public void test5(){
	Scanner scanner = new Scanner(System.in);
	int score = scanner.nextInt();
	System.out.println(score);
	
	scanner.close();
}

//NumberFormatException

public void test4(){
	
	String str = "123";
	str = "abc";
	int num = Integer.parseInt(str);
	
	
	
}

//ClassCastException

public void test3(){
	Object obj = new Date();
	String str = (String)obj;
}

//IndexOutOfBoundsException

public void test2(){

	//StringIndexOutOfBoundsException
	String str = "abc";
	System.out.println(str.charAt(3));
}

2.2编译时运行异常举例

public void test7(){
File file = new File(“hello.txt”);
FileInputStream fis = new FileInputStream(file);

	int data = fis.read();
while(data != -1){
		System.out.print((char)data);
	        data = fis.read();
	}

	fis.close();
	
}

异常处理机制
一:异常处理的两种方式

方式一:try-catch-finally
方式二:throws + 异常类型
try-catch-finally处理模式
//异常处理是通过try-catch-finally语句实现的。

try{
…//可能产生异常的代码

}catch(ExceptionName1e){

    ......//当产生ExceptionName1型异常时的处置措施
        }catch(ExceptionName2e){

    .....//当产生ExceptionName2型异常时的处置措施
}[finally{
    ......//无论是否发生异常,都无条件
    
    }]

try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
catch
在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
throws + 异常类型处理方式
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

注意:

"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!

importjava.io.*;

public class ThrowsTest {

    public static void main(String[] args) {
            
           ThrowsTest t= newThrowsTest();

            try{
                   t.readFile();
                } catch(IOException e) {
                   e.printStackTrace();

                    }
        }

public void readFile() throws IOException {

        FileInputStream in= newFileInputStream("atguigushk.txt");

         int b;
         b= in.read();

        while(b!= -1) {
            
                System.out.print((char) b);
        
                b= in.read();
           }
            in.close();
       }

}
手动抛出异常
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。

首先:首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。

IOExceptione=newIOException();

     throwe;

可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:

throw new String(“want to throw”);
用户自定义异常
一般地,用户自定义异常类都是RuntimeException的子类。
自定义异常类通常需要编写几个重载的构造器。
自定义异常需要提供serialVersionUID
自定义的异常通过throw抛出。
自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
创建多线程的两种方式
继承Thread类的方式
一:实现步骤

创建一个继承股Thread的子类
重写Thread类的run()方法
创建Thread类的子类对象
通过子类对象调用strat()开启线程并调用run()方法;
/**

  • @author 宇戰天
  • @description:遍历1-40之内的偶数
  • @create2020-07-10-16:22
    */

//1.创建一个继承与Thread的子类
class MyThread extends Thread {
//2.重写Thread的run()方法

@Override
public void run() {

    for (int i = 0; i < 40; i++) {
        if(i%2 ==0){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

    }
}

}
public class ThreadTest {

public static void main(String[] args) {
    //3创建Thread的子类对象
    MyThread t1 = new MyThread();

    MyThread t2 = new MyThread();

    //4通过此对象实例调用start()方法开启线程
    t1.start();

    t2.start();

    //创建对比主线程
    for (int i = 0; i < 40; i++) {
        if (i % 2 ==0){
            System.out.println(Thread.currentThread().getName()+":"+i+"  main");
        }

    }




}

}

运行结果

线程的常用方法
start(): 启动线程,并执行对象的run()方法;
run(): 线程在被调度时执行的操作;
getName(): 返回线程的名称;
currentThread:返回执行当前代码的线程;
setName(String name):设置该线程名称;
/**

  • @author 宇戰天

  • @description:

  • 方式一:

  • 设置当前线程的名字setName();

  • 为子线程时对象实例.setName(线程名);设置该线程名

  • 在main方法中设置线程名时需要先通过currentThread()获取当前代码的线程在设置线程名

  • Thread.currentThread().setName(“线程名”);

  • 方式二:

  • 在子类对象中添加Thread(String)的构造器在实例化线程时直接初始化线程名

  • @create2020-07-10-18:42
    */
    public class SetNameMethod {

    public static void main(String[] args) {
    //实例化Thread的子类对象
    UpdateThreadName u1 = new UpdateThreadName();

     u1.setName("我是子线程");
    
     //子类对象调用start()开启线程并调用器run()方法
     u1.start();
    
     //添加主线程对比项
     Thread.currentThread().setName("我是主线程");
    
     for (int i = 0; i < 20; i++) {
    
         if (i % 2 == 0){
             System.out.println(Thread.currentThread().getName() + " " + i);
         }
     }
    

    }
    }

//创建Thread的子类对象
class UpdateThreadName extends Thread{

//提供构造器

public UpdateThreadName() {
}

public UpdateThreadName(String name) {
    super(name);
}

//重写run();
@Override
public void run() {
for (int i = 0; i < 20; i++) {

        if (i % 2 == 0){
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

}

运行结果

  1. yield();释放当前cpu 的执行权限

/**

  • @author 宇戰天

  • @description:

  • yield()释放当前CPU的执行权限

  • @create2020-07-10-19:03
    */
    public class UserYield {

    public static void main(String[] args) {

     YieldMethod y1 = new YieldMethod();
     y1.setName("子线程");
     y1.start();
    
     for (int i = 0; i < 50; i++) {
    
         if (i % 2 != 00){
    
             System.out.println(Thread.currentThread().getName() + "  " + i);
    
         }
    
     }
    

    }

}

class YieldMethod extends Thread{

@Override
public void run() {

    for (int i = 0;i <100;i++){

        if (i % 2 ==0){
            System.out.println(Thread.currentThread().getName() + "  " + i);
        }
        if (i ==20){
            yield();
        }
    }

}

}

join():当某个程序执行流中调用其他线程的join() 方法时,调用线程将被阻塞,直到join() 方法加入的join 线程执行完为止;
isAlive():返回boolean,判断线程是否还活着
sleep(long millis):令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
/**

  • @author 宇戰天

  • @description:

  • join()方法在线程a中调用线程b的join()方法,此时线程a就进入停止状态知道线程b执行完为止
    *sleep();让当前线程休眠,只等时间内为阻塞状态

  • isAlive()判断当前线程是否存活

  • @create2020-07-10-19:28
    */
    public class JoinMethod {

    public static void main(String[] args) {

     JoinIn method23 = new JoinIn();
    
     method23.setName("线程b");
     method23.start();
    
     Thread.currentThread().setName("线程a");
     for (int i = 0; i < 50; i++) {
    
         System.out.println(Thread.currentThread().getName() + "  " + i);
         if (i==25){
             try {
                 //在在线程a中调用线程b的join();
                 method23.join();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
    
         }
    
     }
     //判断当前线程是否存活
     System.out.println(method23.isAlive());
    

    }
    }

class JoinIn extends Thread{

@Override
public void run() {
    for (int i = 0;i<50;i++){

        //当前线程休眠时间
        try {
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + "   " + i);
    }
}

}

线程的优先级
线程的优先级等级

MAX_PRIORITY:10
MIN _PRIORITY:1
NORM_PRIORITY:5(默认优先级)
如何设置线程的优先级
getPriority() :返回线程优先值
setPriority(intnewPriority) :改变线程的优先级
注意
线程创建时继承父线程的优先级;
低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
创建线程的方式二:实现Runnable接口
实现思路
1.创建一个实现Runnable接口的实现类;
2.实现类实现Runnable中的抽象方法run();
3.创建实现类的对象;
4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象;
5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();

/**

  • @author 宇戰天
  • @description:
  • 创建多线程的第二种方式:实现Runnable接口
  • 1.创建一个实现Runnable接口的实现类;
  • 2.实现类实现Runnable中的抽象方法run();
  • 3.创建实现类的对象;
  • 4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象;
  • 5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();
  • @create2020-07-10-21:47
    */

//1.创建一个实现Runnable接口的实现类
class Thread2 implements Runnable{
//2.实现类实现Runnable中的抽象方法run();
@Override
public void run() {
for (int i = 0; i < 40; i++) {

        System.out.println(Thread.currentThread().getName() + " " + i);

    }
}

}
public class ImplementsThreadSecondMethod {

public static void main(String[] args) {
    //3.创建实现类的对象
    Thread2 t2 = new Thread2();
    //4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象
    Thread thread = new Thread(t2);
    thread.setName("线程");
    //5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();
    thread.start();
}

}

线程安全
在java中我们通过同步机制来解决线程的安全问题;解决线程通行常用的三种方法分别为lock锁方式、同步代码块、同步方法

一:同步代码块方式解决线程安全问题
定义
synchronized (同步监听器){

		//需要被同步的代码

}

说明
操作共享数据的代码为需要被同步的代码
共享数据多个线程共同操作的变量
同步监听器:俗称锁任何一个对象都可以充当锁,但是多个线程必须共用同一个锁。
实现Runnable接口方式

/**

  • @author 宇戰天
  • @description:

*通过实现Runnable接口方式创建三个线程实现卖票功能

  • 步骤:
  • 1.创建一个Runnable接口的类;
  • 2.实现Runnable中的抽象方法run();
  • 3.创建实现对象
  • 4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中;
  • 5.通过Thread对象调用start()开启线程
  • 用同步代码块方式解决线程安全问题
  •   synchronized(监听器) {
    
  •          需要同步打代码
    
  • }
    
  • @create2020-07-12-12:31
    */

public class SellTicketTest {

public static void main(String[] args) {
    //3.创建实现的对象
    TicketWindow chengDu = new TicketWindow();

    //4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中

    Thread sellWindows1 = new Thread(chengDu);
    Thread sellWindows2 = new Thread(chengDu);
    Thread sellWindows3= new Thread(chengDu);

    //设置线程名
    sellWindows1.setName("一号窗口");
    sellWindows2.setName("二号窗口");
    sellWindows2.setName("三号窗口");

    //5.通过Thread对象调用start()开启线程
    sellWindows1.start();
    sellWindows2.start();
    sellWindows3.start();

}

}
//1.传建一个实现Runnable接口的子类
class TicketWindow implements Runnable{
//售票数量(多个线程共享此数据)
private int ticket =100;

//定义同步监听器-->锁
Object obj = new Object();

//2.重写Runnable中的抽象方法run()
@Override
public void run() {
    while (true){

        synchronized(obj) {

            if (ticket >0){
//一秒后开启线程为其他线程执行抢占CPU资源提供条件
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + " 卖票,票的编号为:" + ticket);

                ticket--;
            }else{
                break;
            }
        }

    }
}

}

继承Thread类

**

  • @author 宇戰天

  • @description:

  • 通过继承Thread方式创建三个进程实现卖票功能

  • 1.创建继承Thread的子类;

  • 2.重写T和read中的run();

  • 3.创建Thread的子类对象;

  • 4.通过子类对象调用start()方法开启线程

  • 通过synchronized(同步监视器){

  • 需要被同步的代码
    
  • }

  • 解决线程安全问题

  • @create2020-07-12-13:28
    */
    public class SellTicketTest1 {

    public static void main(String[] args) {
    //3.创建Thread类的子类的对象
    sellWindows1 t1 = new sellWindows1();
    sellWindows1 t2 = new sellWindows1();
    sellWindows1 t3 = new sellWindows1();

     //更改线程名
     t1.setName("窗口1");
     t2.setName("窗口2");
     t3.setName("窗口3");
    
     //4.通过此子类对象调用start()开启线程
     t1.start();
     t2.start();
     t3.start();
    

    }
    }

//1.创建一个继承于Thread的子类
class sellWindows1 extends Thread{
//所有对象共享此变量
private static int ticket = 100;
//创建同步锁
private static Object obj = new Object();
//2.重写Thread中的run
@Override
public void run() {

    while (true){

        synchronized (obj){
            if (ticket>0){

                    //提高其他线程出现的几率
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 卖票,票号为:" + ticket);
                ticket--;

            }else{
                break;
            }
        }

    }
}

}

同步方法解决线程安全问题
实现Runnable接口方式

/**

  • @author 宇戰天

  • @description:

  • 同步方法解决线程安全问题

  • @create2020-07-12-14:13
    */
    public class SellTicketTest3 {

    public static void main(String[] args) {
    //3.创建实现的对象
    TicketWindow3 chengDu = new TicketWindow3();

     //4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中
    
     Thread sellWindows1 = new Thread(chengDu);
     Thread sellWindows2 = new Thread(chengDu);
     Thread sellWindows3 = new Thread(chengDu);
    
     //设置线程名
     sellWindows1.setName("一号窗口");
     sellWindows2.setName("二号窗口");
     sellWindows2.setName("三号窗口");
    
     //5.通过Thread对象调用start()开启线程
     sellWindows1.start();
     sellWindows2.start();
     sellWindows3.start();
    

    }

}
//1.传建一个实现Runnable接口的子类
class TicketWindow3 implements Runnable{
//售票数量(多个线程共享此数据)
private int ticket =100;

//2.重写Runnable中的抽象方法run()
@Override
public void run() {
    while (true) {

        show();

    }
}
private synchronized void show(){

    if (ticket >0){
        //一秒后开启线程为其他线程执行抢占CPU资源提供条件
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 卖票,票的编号为:" + ticket);

        ticket--;
    }
}

}

继承Thread子类的方式

/**

  • @author

  • @description:

  • @create2020-07-12-14:35
    */
    public class sellTicketTest4 {

    public static void main(String[] args) {
    //3.创建Thread类的子类的对象
    sellWindows4 l1 = new sellWindows4();
    sellWindows4 l2 = new sellWindows4();
    sellWindows4 l3 = new sellWindows4();

     //更改线程名
     l1.setName("窗口1");
     l2.setName("窗口2");
     l3.setName("窗口3");
    
     //4.通过此子类对象调用start()开启线程
     l1.start();
     l2.start();
     l3.start();
    

    }
    }

//1.创建一个继承于Thread的子类
class sellWindows4 extends Thread{
//所有对象共享此变量
private static int ticket = 100;

//2.重写Thread中的run
@Override
public void run() {

    while (true){

        show();

    }
}

private static synchronized  void show(){
    if (ticket>0){

        //提高其他线程出现的几率
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 卖票,票号为:" + ticket);
        ticket--;

    }

}

}

线程通信
wait() 与notify() 和notifyAll()

wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
注意
这三个方法只有在synchronized方法或synchronized代码块中才能使用

一:定义
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

二: 内置注解
作用在代码的注解是

@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:

@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
自定义注解
① 注解声明为:@interface
② 内部定义成员,通常使用value表示
③ 可以指定成员的默认值,使用default定义
④ 如果自定义注解没成员,表明是一个标识作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值