今天遇到个需求,可能有同时两个方法写入同一个excel。


怎么能让一个方法同时被调用,创建线程就行了

首先是一个方法被同时调用,开始我还不会怎么能让一个方法被同时执行。后来搜到创建线程就行了。
需要同时执行的方法像下面createExcelFile()这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public synchronized static void createExcelFile(String excelPath) throws IOException {

if (!excelFileExisted) {//false可能是1.没文件没布尔;2.有文件没布尔

File file = new File(excelPath);
if (file.createNewFile()) {//没文件没布尔
System.out.println("文件创建成功");
XSSFWorkbook workbook = new XSSFWorkbook();
FileOutputStream outputStream = new FileOutputStream(excelPath);
workbook.write(outputStream);
outputStream.close();

} else {//有文件没布尔
}
excelFileExisted = true;


} else {
System.out.println("文件已经存在.");


}

}

new Thread长这样

1
2
3
4
5
6
Thread threadOne = new Thread(new Runnable() {
@SneakyThrows
public void run() {
createExcelFile(excelPath);
}
});

为什么用匿名内部类的形式创建thread及两种实现多线程的基本方式

本来向main里抛出异常,main直接调用createExcelFile()没啥事但是,这么创建thread就报错了,加了@SneakyThrows就行了。为什么呢?大概是因为thread是以内部类形式创建的。(那我现在去看下内部类https://www.cnblogs.com/dolphin0520/p/3811445.html )发现有成员内部类 局部内部类 匿名内部类。这个属于匿名内部类。不对啊 虽然下面这种形式也是可以的,但是还是要加@SneakyThrow,为什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
static class Runnable1 implements  Runnable{

@SneakyThrows
public void run() {
createExcelFile(excelPath);
createSheetAndTitle(excelPath, machineSheetName, titles);
ArrayList<String[]> list = new ArrayList<String[]>();
list.add(new String[]{"1", "F:0.756", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())});
list.add(new String[]{"1", "E:0.933", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())});

addRows(excelPath, machineSheetName, list);
}
}

这种写法虽然能达到一样的效果,但是既冗长又难以维护。
那么问题来了,使用匿名内部类创建线程的好处是什么?但是,如果一个只使用一次,那么将其编写为独立的一个类岂不是很麻烦?这个时候就应该想到匿名内部类了,匿名内部类就此诞生了!
不得不说匿名方法最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口。
首先,多线程的实现方式两种:一种是继承Thread类,另一种是实现Runnable接口。
Thread类是Runnable接口的一个实现类
看两种实现多线程的基本方式(不实用匿名内部类)

继承Thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyThread extends Thread{
private int ticket = 5;
public void run(){
for(int i = 0;i<100;i++){
if(ticket>0){//判断是否还有剩余票
System.out.println("卖票,ticket = "+ticket--);
}
}
}
};
public class ThreadDemo04{
public static void main(String args[]){
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
mt1.start();//调用线程主体让其运行
mt2.start();//三个地方同时卖票
mt3.start();
}
};

实现Runnable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyThread implements Runnable{
private int ticket=5;
public void run(){
for(int i = 0;i<100;i++){
if(ticket>0){
System.out.println("卖票,ticket = "+ticket--);
}
}
}
};
public class RunnableDemo02{
public static void main(String args[]){
MyThread my1 = new MyThread();
new Thread(my1).start(); //启动三个线程
new Thread(my1).start(); //共享my1中资源
new Thread(my1).start();
}
};

可知最后:无论哪种方法都需要实现run()方法,run方法是线程的运行主体。并且,线程的运行都是调用Thread的start()方法。
那么代理模式中Thread类就充当了代理类,它在线程运行主体运行前作了一些操作然后才运行线程的run()。总之,Thread提供了很多有关线程运行前、后的操作,然后通过它的start()方法让JVM自动调用目标的run()方法。


static不能向上抛出异常了

之前的问题为什么不能向上抛出呢?跟匿名内部类没有一点关系
是因为静态代码块中的异常原则上必须处理,不应该也不能再往上抛
原因:在类加载器,加载该类时,首先执行的就是static{}块中的代码,如果static{}块中的异常没有处理,异常就会导致该类加载失败,也就是说“该类夭折,不存在”,显然与其相关的操作肯定就不能执行当然了,如果你“不得不”向外抛可以这样写:(用InputStream举例,可根据你自己的代码修改一下)
https://bbs.csdn.net/topics/310071083

1
2
3
4
5
6
7
8
static {
try {
InputStream inputStream = new FileInputStream("");
} catch (FileNotFoundException e) {
// 抛出 运行式异常 (这样写,实质上也应该算是处理了异常)
throw new RuntimeException(e);
}
}

即使不是static,实现Runnable接口不能抛异常只能捕获异常

我去掉static发现还是不能抛,为什么?
因为run()方法是Runnable接口里面的方法,而Runnable接口在定义run()方法的时候没有抛出任何异常,所以子类在重写run()方法的时候要小于或等于父类(Runnable)的run()方法的异常,所以父类没有抛出异常,子类不能抛出异常

那我上面说的static不能抛到底是不是对的啊?好像完全没有问题啊。static方法完全可以抛出异常啊。那上一段我就划掉了。


main里不能访问实例方法,只能静态方法

顺便插一嘴因为main是static,所以不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。


java中方法必须写在类体里

再顺便插一嘴,java中方法必须写在类体里。我他妈居然才知道。


为什么要向上转型而不是直接声明子类引用(Dog dog=new Dog())?

比如设计一个父类 FileRead 用来读取文件,ExcelRead 类和 WordRead 类继承 FileRead 类。在使用程序的时候,往往事先不知道我们要读入的是 Excel 还是 Word。所以我们向上转型用父类去接收,然后在父类中实现自动绑定,这样无论你传进来的是 Excel 还是 Word 就都能够完成文件读取。

下面两篇关于为什么不要声明子类引用讲得挺好的 内容差不多 忘了多看看。
https://blog.csdn.net/TNTZS666/article/details/80273986
http://c.biancheng.net/view/6521.html

可是我试了试上面说的,发现纯属放屁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

public static void show(ADCarry adCarry) {
adCarry.duiXian();
adCarry.faYu();
}


public static void main(String[] args) {


ADCarry uzi2 = new Uzi();
show(uzi2);//正确

Uzi uzi = new Uzi();
show(uzi);//你他妈怎么也正确啊




;


}