Struts:Action
Spring,Spring Boot
Hibernate:
Hibernate是开源的一个ORM(对象关系映射)框架
Hibernate对JDBC访问数据库的代码做了轻量级封装
Java Persistence API (JPA)
H2: in-memory database(),包名:com.h2database
Model、Dao、
MyBatis:
主要使用XML配置。
Thread的join()方法
主线程等待子线程的终止。也就是说主线程的代码块中,如果碰到了t.join()方法,此时主线程需要等待(阻塞),
等待子线程结束了(Waits for this thread to die.),才能继续执行t.join()之后的代码块。
示例:https://www.cnblogs.com/skywang12345/p/3479275.html
这里使用了一个延时for循环模拟长时间的执行操作。
public class JoinTest{
public static void main(String[] args){
/*
try {
ThreadA t1 = new ThreadA("t1"); // 新建“线程t1”
t1.start(); // 启动“线程t1”
t1.join(); // 将“线程t1”加入到“主线程main”中,并且“主线程main()会等待它的完成”
System.out.printf("%s finish\n", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
ThreadA t1 = new ThreadA("t1"); // 新建“线程t1”
t1.start();
System.out.printf("%s finish\n", Thread.currentThread().getName());
}
static class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
public void run(){
System.out.printf("%s start\n", this.getName());
// 延时操作
for(int i=0; i <1000000; i++)
;
System.out.printf("%s finish\n", this.getName());
}
}
}
当不注释掉注释时,主线程main的finish方法会等待子线程t1执行完再执行:
当注释掉注释时,主线程main的finish方法会在子线程t1前执行:
哪个Thread对象调用的join(),main线程就等待哪个子线程执行完成。
Thread的run()方法和start()方法的区别
示例:https://www.cnblogs.com/skywang12345/p/3479083.html
// Demo.java 的源码
class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
public void run(){
System.out.println("[*] 某线程:" + Thread.currentThread().getName()+" is running");
}
};
public class Demo {
public static void main(String[] args) {
Thread mythread=new MyThread("mythread");
System.out.println("[*] 某线程:" + Thread.currentThread().getName()+" 调用 mythread.run()");
mythread.run();
System.out.println("[*] 某线程:" + Thread.currentThread().getName()+" 调用 mythread.start()");
mythread.start();
}
}
可见如果在main方法中直接调用mythread对象的run方法,则其实是main线程里调用了另外一个对象的某个方法而已。而如果是在main方法中调用mythread对象的start方法,则会先开启一个线程mythread,然后再执行其run方法。
synchronized原理
synchronized代码块
例如,synchronized(obj)就获取了“obj这个对象”的同步锁。
通过同步锁,我们可以互斥地访问某方法/对象。
同步锁的作用体现在:某一时刻,某线程A已经获取到了“obj这个对象”的同步锁,在执行一些操作。如果这个时候某线程B也尝试获取“obj这个对象”的同步锁,则会失败。
示例:https://www.cnblogs.com/skywang12345/p/3479202.html
class MyRunable implements Runnable {
@Override
public void run() {
//synchronized(this) {
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(1000); // 休眠1000ms
System.out.println(Thread.currentThread().getName() + " loop " + i);
}
} catch (InterruptedException ie) {
}
//}
}
}
class Demo1_1 {
public static void main(String[] args) {
Runnable demo = new MyRunable(); // 新建“Runnable对象”
Thread t1 = new Thread(demo, "t1"); // 新建“线程t1”, t1是基于demo这个Runnable对象
Thread t2 = new Thread(demo, "t2"); // 新建“线程t2”, t2是基于demo这个Runnable对象
t1.start(); // 启动“线程t1”
t2.start(); // 启动“线程t2”
}
}
可见,加了之后,t2会等待t1结束之后才会执行。
而不加的话,t2会在t1执行过程中就执行。
这里之所以使用synchronized(this)
之后,可以将两个线程互斥,是因为这两个Thread都使用了demo这个对象的run方法。
而如果修改示例代码如下:
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
//synchronized(this) {
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(1000); // 休眠100ms
System.out.println(Thread.currentThread().getName() + " loop " + i);
}
} catch (InterruptedException ie) {
}
//}
}
}
class Demo1_2 {
public static void main(String[] args) {
Thread t1 = new MyThread("t1"); // 新建“线程t1”
Thread t2 = new MyThread("t2"); // 新建“线程t2”
t1.start(); // 启动“线程t1”
t2.start(); // 启动“线程t2”
}
}
这里使用的是两个不同的Thread,没有共享一个Runnerable对象。所以synchronized功能没有发挥到作用。
synchronized方法 和 synchronized代码块
“synchronized方法”是用synchronized修饰的方法,而 “synchronized代码块”则是用synchronized修饰的代码块。
synchronized方法示例
public synchronized void foo1() {
System.out.println("synchronized methoed");
}
synchronized代码块
public void foo2() {
synchronized (this) {
System.out.println("synchronized methoed");
}
}