时隔这么久,那个菜鸟又回来了

文章目录

  • 多线程
    • 程序、进程、线程
      • 线程的创建和使用
        • 一、多线程的创建:方式一:继承于Thread类
        • 二、线程的常用方法
        • 三、例题:创建3个窗口买票,票数为100,使用继承Thread的方式
        • 四、多线程的创建:方式二:实现Runable接口
        • 五、例题:创建3个窗口买票,票数为100,使用实现Runnable的方式
        • 六、两种创建方式的对比
      • 线程的生命周期
      • 线程的同步
        • 解决线程安全问题的方式一、二
      • 解决线程安全问题的方式三:Lock锁---JDK5.0新增
      • 线程的死锁
      • 线程的通信
      • JDK5.0新增线程创建方式
        • 一、多线程的创建:方式三:实现Callable接口
        • 二、多线程的创建:方式四:使用线程池(开发中常用)

多线程

程序、进程、线程

  • 程序:一段静态的代码
  • 进程:是程序的一次执行过程。或是正在运行的一个程序。是一个动态的过程
    • 进程作为资源分配的单位
  • 线程:进程可进一步细化为线程,是一个程序内部的一条执行路径
    • 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器
    • 一个线程中的多个线程共享相同的内存单元/内存地址空间–>他们从同一堆中分配对象,可以访问相同的变量和对象。使得线程间通信更简洁,高效。但多线程操作可能会带来安全隐患

线程的创建和使用


一、多线程的创建:方式一:继承于Thread类

  1. 创建一个继承于Thread类的子类

  2. 重写Thread类的run() 方法

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

  4. 通过此对象调用start()

例子:遍历100以内的所有的偶数

//1.创建一个继承于Thread类的子类
class MyThread extends Thread {//2.重写Thread类的run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() + ":" +i); //获得当前的线程名}}}
}public class ThreadTest {public static void main(String[] args) {//3.创建Thread类的子类的对象MyThread myThread = new MyThread();//4.通过此对象调用start() 作用:①启动当前线程 ②调用当前线程的run()myThread.start();//问题一:我们不能通过直接调用run()的方式启动线程//myThread.run();//这样根本就没有启动线程,还是main的线程,这里还是体现的是对象调方法//问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行,会报IllegalThreadException//myThread.start();//需要重新创建一个线程的对象MyThread myThread2 = new MyThread();myThread2.start();for (int i = 0; i < 100; i++) {if (i % 2 != 0) {System.out.println(Thread.currentThread().getName() + ":" +i); //获得当前的线程名}}}
}

另一种简单写法,创建Thread的匿名子类匿名对象

public class ThreadTest {public static void main(String[] args) {new Thread() {@Overridepublic void run() {}}.start();}
}

总结:要想创建多个线程就要创建多个对象,要想启动线程就要通过start()方法。

二、线程的常用方法

1.start():启动当前线程:调用当前线程的run()方法

2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明再此方法中

3.currentThread():静态方法,返回执行当前代码的线程

4.getName():获取当前线程的名字

5.setName():设置当前线程的名字 //给主线程改名:Thread.currentThread().setName(“主线程”);

//也可以通过构造器个线程命名,在子类中写一个带参的构造器,调用父类带参的构造器

6.yield():释放当前cpu的执行权(但是在下一刻当前线程可能又会被分配到执行权)

7.join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。

8.stop():已过时。当执行此方法时,强制结束当前线程

9.sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态

10.isAlive():判断当前线程是否存活

11.getPriority():获取线程的优先级

12.setPriority(int p):设置线程的优先级

13.线程的优先级:

**说明:*高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。 并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

/*** 测试Thread中的常用方法* @author ZAQ* @create 2020-02-05 14:21*/
class HelloThread extends Thread {public HelloThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0) {//sleep()测试try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + getPriority() + ": " + i);}//yield()测试if(i % 20 == 0) {yield();}}}
}
public class ThreadMethodTest {public static void main(String[] args) {HelloThread h1 = new HelloThread("Thread:1");//设置分线程的优先级h1.setPriority(Thread.MAX_PRIORITY);h1.start();//给主线程命名Thread.currentThread().setName("主线程");//设置主线程的优先级Thread.currentThread().setPriority(Thread.MIN_PRIORITY);for (int i = 0; i < 100; i++) {if(i % 2 == 0) {                                                                      System.out.println(Thread.currentThread().getName() + ":" +                     getPriority() + ": " + i);}//join()测试if(i == 20) {try {h1.join();} catch (InterruptedException e) {e.printStackTrace();}}}//isAlive()测试System.out.println(h1.isAlive());}
}

三、例题:创建3个窗口买票,票数为100,使用继承Thread的方式

*** 创建3个窗口买票,票数为100* 存在线程安全问题,待解决。* @author ZAQ* @create 2020-02-05 16:37*/class Window extends Thread {private static int ticket = 100; //每个对象共享同一个变量,不设置为static的将会有300张票@Overridepublic void run() {while (true) {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "卖票:票号为:" + 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("Window1");window2.setName("Window2");window3.setName("Window3");window1.start();window2.start();window3.start();}}

四、多线程的创建:方式二:实现Runable接口

  1. 创建一个实现了Runnable接口
  2. 实现类去实现Runnable中的抽象类方法:run()
  3. 创建实现类的对象
  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  5. 通过Thread类的对象调用start()
/*** 多线程的创建:方式二:实现Runable接口** @author ZAQ* @create 2020-02-05 17:01*///1. 创建一个实现了Runnable接口
class MThread implements Runnable {//    2. 实现类去实现Runnable中的抽象类方法:run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}public class ThreadTest1 {public static void main(String[] args) {//3. 创建实现类的对象MThread mThread = new MThread();//4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象Thread thread = new Thread(mThread);//5. 通过Thread类的对象调用start() ①:启动线程  ②:调用当前线程run()方法 --> 调用了Runnable类型的target的run()方法thread.start();//通过源码可知:这里Thread里的run()方法就是调用target的run()方法,而生成对象初始化时将传进来的mThread赋给了targer,// 所以这里通过thread调用的start方法调用的run()方法就是调用MThread重写的run()方法//在启动一个线程,遍历100以内的偶数Thread t2 = new Thread(mThread);t2.start();}
}

另一种简单写法:匿名的方式实现Runnable接口

public class ThreadTest {public static void main(String[] args) {new Thread(new Runnable() {/*Runnable实现类的匿名对象对象*/@Overridepublic void run() {}}).start();}
}

五、例题:创建3个窗口买票,票数为100,使用实现Runnable的方式

/*** 存在线程安全问题,暂不考虑* @author ZAQ* @create 2020-02-05 17:37*/class Windows implements Runnable {private int ticket = 100; //不加static也只有100张票,原因看下面注释@Overridepublic void run() {while (true) {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "卖票:票号为:" + ticket--);} else {break;}}}
}public class WindowTest1 {public static void main(String[] args) {Windows w = new Windows(); //这是因为这里都共用一个对象Thread thread1 = new Thread(w);Thread thread2 = new Thread(w);Thread thread3 = new Thread(w);thread1.setName("Windows1");thread2.setName("Windows2");thread3.setName("Windows3");thread1.start();thread2.start();thread3.start();}
}

六、两种创建方式的对比

开发中:优先选择:实现Runable接口的方式

原因:

  • 实现的方式没有类的单继承的局限性(继承的Thread方式将没有办法继承其他类,实现的方式还可继承其他类,或其他方法)
  • 实现的方式更合适来处理多个线程有共享数据的情况

联系:Thread也是实现Runnable接口

相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。

线程的生命周期


新建:当一个Thread类或其子类的对象被声明或创建时,新生的线程对象处于创建状态

就绪:处于创建状态的线程被start()后,将进入线程队列等待CPU时间片,此时他已具备了运行的条件,只是没分配到CPU资源

运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能

阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态

死亡:线程完成了他的全部工作或线程被提前强制地终止或出现异常导致结束

线程的同步


问题提出

  • 多个线程执行的不确定性引起执行结果的不确定
  • 多个线程对账本的共享,会造成操作的不完整性,会破坏数据。

解决线程安全问题的方式一、二

例子:创建三个窗口卖票,总数为100张,使用实现Runnable接口的方法。

  1. 在Java中,我们通过同步机制,来解决线程的安全问题

方式一:同步代码块

synchronized(同步监视器) {//需要被同步的代码
}

​ 说明:

​ ① 操作共享的数据的代码,即为需要被同步的代码

​ ② 共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。

​ ③ 同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。

要求:多个线程必须要共用用一把锁

​ 补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

方式二:同步方法

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的

说明:

​ ① 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。

​ ② 非静态的同步方法,同步监视器:this

​ 静态的同步方法,同步监视器是:当前类本身

  1. 同步的方式,解决了线程的安全问题。 ------好处

操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。------局限性

实例一:使用**同步代码块的方式解决实现Runnable接口**的线程安全问题

/*** 1.问题:卖票的过程中,出现了重票、错票(0、-1) --> 出现了线程的安全问题* 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。* 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来,直到线程a操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。* @author ZAQ* @create 2020-02-06 16:16*/ class Windows implements Runnable {private int ticket = 100;Object obj = new Object();//创建一把锁@Overridepublic void run() {//Object obj = new Object(); 锁不能在这里声明,这里就相当于创建了三把锁while (true) {synchronized(obj) {//也不能在这里new Object()   使用this是可以的if (ticket > 0) {try {Thread.sleep(100);//一个线程进入,在这里睡着了。其他的线程这时就会进入,产生安全问题//注意:这里就是不休眠也存在安全问题,只是概率比较低,在这里执行休眠,只是让这个概率提升了} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖票:票号为:" + ticket--);} else {break;}}}}
}public class WindowTest1 {public static void main(String[] args) {Windows w = new Windows();Thread thread1 = new Thread(w);Thread thread2 = new Thread(w);Thread thread3 = new Thread(w);thread1.setName("Windows1");thread2.setName("Windows2");thread3.setName("Windows3");thread1.start();thread2.start();thread3.start();}
}

实例二:使用**同步代码块的方式解决继承Thread**的线程安全问题

说明:在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。

/*** 使用同步代码块的方式解决继承Thread的线程安全问题*说明:在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视   器。* @author ZAQ* @create 2020-02-06 16:59*/class Windows2 extends Thread {private static int ticket = 100;private static Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) { //正确的方式//synchronized (Windows2.class) {正确的方式二:Class clazz = Windows2.class。Windows2.class只会加载一次!//synchronized (this) { //错误的方式:this代表着w1,w2,w3三个对象,三把锁if(ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + ": " + ticket--);} else {break;}}}}
}public class WindowTest2 {public static void main(String[] args) {Windows2 w1 = new Windows2();Windows2 w2 = new Windows2();Windows2 w3 = new Windows2();w1.setName("窗口一:");w2.setName("窗口二:");w3.setName("窗口三:");w1.start();w2.start();w3.start();}
}

实例三:使用**同步方法解决实现Runnable接口**的线程安全问题

/*** 使用同步方法解决实现Runnable接口的线程安全问题** @author ZAQ* @create 2020-02-06 16:52*/class Windows3 implements Runnable {private int ticket = 100;Object obj = new Object();boolean flag = true;@Overridepublic void run() {while (flag) {show();}}private synchronized void show() { //同步监视器:this。因为this是唯一的if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖票:票号为:" + ticket--);} else {flag = false;}}
}public class WindowTest3 {public static void main(String[] args) {Windows3 w = new Windows3();Thread thread1 = new Thread(w);Thread thread2 = new Thread(w);Thread thread3 = new Thread(w);thread1.setName("Windows1");thread2.setName("Windows2");thread3.setName("Windows3");thread1.start();thread2.start();thread3.start();}
}

实例四:使用**同步方法的方式解决继承Thread**的线程安全问题

/*** @author ZAQ* @create 2020-02-06 17:43*/class Windows4 extends Thread {private static int ticket = 100;private static boolean flag = true;@Overridepublic void run() {while (flag) {show();}}private static synchronized void show() {//同步监视器:Windows4.class//private synchronized void show() {//同步监视器:w1,w2,w3。有三个锁,此解决方式是错的if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ": " + ticket--);} else {flag = false;}}
}public class WindowTest4 {public static void main(String[] args) {Windows4 w1 = new Windows4();Windows4 w2 = new Windows4();Windows4 w3 = new Windows4();w1.setName("窗口一:");w2.setName("窗口二:");w3.setName("窗口三:");w1.start();w2.start();w3.start();}
}

实例五:线程安全的单例模式——懒汉式

/*** 线程安全的懒汉式* @author ZAQ* @create 2020-02-06 19:21*/
public class BankTest {public static void main(String[] args) {}
}class Bank {private Bank() {}private static Bank bank;public static Bank getBank() {//方式一:效率稍差(不管有没有给bank实例化上对象,进来的线程都需要等待)
//        synchronized (Bank.class) {//            if(bank == null) {//                bank = new Bank();
//            }
//            return bank;
//        }//方式二:效率更高if(bank == null) {synchronized (Bank.class) {if(bank == null) {bank = new Bank();}}}return bank;}
}

解决线程安全问题的方式三:Lock锁—JDK5.0新增

  1. 实例化ReentrantLock
  2. 在try代码块中调用上锁方法lock()
  3. 在finally代码块中调用解锁方法unlock()

实例六:

/*** @author ZAQ* @create 2020-02-06 21:04*/class Lock implements Runnable{private int ticket = 100;private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {try {lock.lock();while (true) {if(ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ": " + ticket--);} else {break;}}} finally {lock.unlock();}}
}public class LockTest {public static void main(String[] args) {Lock lock = new Lock();Thread thread1 = new Thread(lock);Thread thread2 = new Thread(lock);Thread thread3 = new Thread(lock);thread1.setName("窗口一");thread2.setName("窗口二");thread3.setName("窗口三");thread1.start();thread2.start();thread3.start();}
}

线程的死锁


  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
  • 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

线程的通信


涉及到三个方法:

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器(锁)。
  • notify():一旦执行此方法,就会唤醒wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个线程。
  • notifyAll():一旦执行此方法,就会唤醒wait的所有线程。

说明:

  • wait()、notify()、notifyAll()三个方法必须使用在同步代码块或同步方法中。

  • wait()、notify()、notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现ILLegalMonitorStateException异常。

  • wait()、notify()、notifyAll()三个方法定义在java.lang.Object类中

例子:使用两个线程打印 1-100。线程1,线程2 交替打印

/*** @author ZAQ* @create 2020-02-06 22:36*/class Number implements Runnable {private int number = 1;private Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) {obj.notify();if (number <= 100) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ": " + number++);} else {break;}try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}
}public class CommunicationTest {public static void main(String[] args) {Number number = new Number();Thread thread1 = new Thread(number);Thread thread2 = new Thread(number);thread1.setName("线程一");thread2.setName("线程二");thread1.start();thread2.start();}
}

JDK5.0新增线程创建方式


一、多线程的创建:方式三:实现Callable接口

与使用Runable相比,Callable功能更强大些

  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,比如获取返回结果

创建过程

  1. 创建一个实现Callable的实现类
  2. 实现call方法,将此线程需要执行的操作声明在Call()中
  3. 创建Callable接口实现类的对象
  4. 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
  5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
  6. 获取Callable中的call方法的返回值 (可有可无get(),根据实际情况,看需不需要call的返回值)
/*** @author ZAQ* @create 2020-02-07 12:43*///1. 创建一个实现Callable的实现类
class NumThread implements Callable<Integer> {//    2. 实现call方法,将此线程需要执行的操作声明在Call()中@Overridepublic Integer 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 ThreadNew {public static void main(String[] args) {//        3. 创建Callable接口实现类的对象NumThread numThread = new NumThread();
//        4. 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象FutureTask<Integer> futureTask = new FutureTask<>(numThread);
//        5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()Thread thread = new Thread(futureTask);thread.start();try {//            6. 获取Callable中的call方法的返回值 (可有可无get(),根据实际情况,看需不需要call的返回值)//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值Integer sum = futureTask.get();System.out.println("总和为:" + sum);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}

如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?

  • call()可以有返回值。
  • call()可以抛出异常,被外面的操作捕获,获取异常的信息。run()方法不能抛出异常
  • Callable是支持泛型的。

二、多线程的创建:方式四:使用线程池(开发中常用)

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。

没有线程池就相当于:如果我要去天安门广场,需要一个交通工具,自行车,这时我就需要自己造一辆自行车,到了天安门以后,再将自行车销毁。如果有了线程池,就相当于共享单车。自行车已将造好了,如果我需要的的时候只需要去拿就行了,用完了再放回去。

使用线程池的好处:

  • 提高了响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程, 不需要每次都创建)
  • 便于线程管理(如果每个人都自己造一个线程将会产生拥堵)
    • corePoolSize:线程池的大小
    • maximumPoolSize:最大线程数

代码实现

/*** @author ZAQ* @create 2020-02-07 13:41*/class NumberThread implements Runnable{@Overridepublic void run() {for(int i = 0; i < 100; i++) {if(i % 2 == 0) {System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}class NumberThread1 implements Runnable{@Overridepublic void run() {for(int i = 0; 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 service = Executors.newFixedThreadPool(10);ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;//设置线程池的属性service1.setCorePoolSize(2);//2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象//提供两个线程完成不同的操作service1.execute(new NumberThread()); //适合使用于Runnableservice1.execute(new NumberThread1()); //适合使用于Runnable//service.submit(Callable callable); //适合使用于Callable//3.关闭连接池service1.shutdown();}
}

菜鸟学JAVA之——多线程相关推荐

  1. 菜鸟学Java(六)——简单验证码生成(Java版)

    转载自  菜鸟学Java(六)--简单验证码生成(Java版) 验证码大家都知道,它的作用也不用我多说了吧.如果不太清楚请参见百度百科中的解释,一般验证码的生成就是随机产生字符(数字.字母或者汉字等) ...

  2. 【零基础学Java】—多线程(四十九)

    [零基础学Java]-多线程(四十九) 一.并发与并行 并发:指两个或多个事件在同一时间段内发生 并行:指两个或多个事件在同一时刻发生(同时发生) 二.进程和线程

  3. java多线程绘图_菜鸟学Java之 Java2D 多线程绘图

    1 绘制动态连线. 我需要在画布的两点间绘制一条可动态展示(连线可以一段段的按时间增长)的连线,于是我打算使用多线程进行绘制,于是我建立了一个自己的线程类: class MyThread implem ...

  4. 菜鸟学Java笔记1

    这两天通过视频和书籍在自学java.每天学一点,每天做一点笔记,希望有所收获! 1,Java运行中的内存分配 理解内存的分配,也就理解了一切.对于java而言,内存分为四块:代码区(code)/数据区 ...

  5. java做一个mud_菜鸟学Java(十二)——搭建一个完整的Java开发环境

    作为一个Java程序员,配置一个java开发环境是必备的技能,今天给广大菜鸟初学者补上一课.环境的配置,大概就分三个1,JDK 2,Tomcat(或者其他的)3,eclipse(或者myeclipse ...

  6. 菜鸟学Java(二十一)——如何更好的进行单元测试——JUnit

    测试在软件生命周期中的重要性,不用我多说想必大家也都非常清楚.软件测试有很多分类,从测试的方法上可分为:黑盒测试.白盒测试.静态测试.动态测试等:从软件开发的过程分为:单元测试.集成测试.确认测试.验 ...

  7. 菜鸟学java ——(一)面向对象程序设计(几个重要的概念)

    几个概念的解释: (1)面向对象(OOP:程序由对象组成,每个对象中包括功能部分和实现部分.面向对象关心能否满足用户需求,而非对象的具体实现.在OOP思想中数据被放在第一位,而操作数据的算法被放在第二 ...

  8. 菜鸟学java要多久_菜鸟学java,根本停不下来!

    位运算符 &: 两个2进制的操作数,同一位数的两个数如果有一个为0结果就为0,两个都为1才是1. | : 两个2进制的操作数,同一位数的两个数如果有一个为1,两个都为0才是0. ^ : 两个2 ...

  9. 菜鸟学JAVA之——常用类(StringBuffer、StringBuilder、Comparable、Comparator等)

    文章目录 常用类 字符串相关的类 一.String类及常用方法 二.StringBuffer.StringBuilder JDK 8 之前的日期时间API 一.System静态方法 二.Date类 三 ...

  10. 菜鸟学Java——简单验证码生成(Java版)

    验证码大家都知道,它的作用也不用我多说了吧.如果不太清楚请参见百度百科中的解释,一般验证码的生成就是随机产生字符(数字.字母或者汉字等),然后将这些生成的字符绘制成一张图片,再在图片上加上一些干扰元素 ...

最新文章

  1. PTA 基础编程题目集 7-13 日K蜡烛图 C语言
  2. 什么是StackOverflowError?
  3. 常考数据结构与算法:将字符串转为整数
  4. Sublime Text3激活
  5. PMP知识点(六、质量管理)
  6. 5个实用提速深度学习模型的方法
  7. POJ 2176 Folding(区间DP)
  8. json-lib解析json之二维JSONArray
  9. 单反相机坏点和噪点测试软件,单反相机测试坏点和噪点的软件
  10. 使用ntsd命令强制性杀掉进程[微软未开公的密秘]
  11. MFC+Opencv以图拼图
  12. java横向导出excel_java 生成导出Excel文件
  13. java 霍夫变换_霍夫变换(Hough Transform)
  14. 水电设计院信息管理系统1.0
  15. windows 磁盘管理:简单卷、跨区卷、带区卷、镜像卷 和 RAID-5
  16. java8的sorted,Java8排序stream.sorted()
  17. 面试结束时应该向面试官提出什么问题
  18. 二次开发crmeb增加实名认证 20220331
  19. Windows xp sp3简体中文正式版下载地址
  20. 高德地图-初始化的时候获取行政区边界和中心点

热门文章

  1. 免费pdf转word网页版
  2. ssh服务端配置了authorized_keys,免密登录失败
  3. eclipse修改自定义皮肤
  4. 梯形公式预测校正matlab_鲁棒预测控制(Robust MPC)
  5. 如何保证战略落地_如何保障企业战略落地实施
  6. 【星门跳跃】解题报告
  7. 00 SQL课程简介
  8. 包饺子、看表演、逛庙会 中外居民北京“过大年”
  9. B. Alice and the List of Presents(组合数学)
  10. Python语法练习