Java 基础知识点 笔记总结

Posted IT_Holmes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 基础知识点 笔记总结 相关的知识,希望对你有一定的参考价值。

1. Intellij IDEA 软件使用


和eclipse不同的简写方式:

  • psvm = main方法。
  • sout = System.out.println();
public class TestStart {
    //psvm等于下面的main方法
    public static void main(String[] args) {
        //"hello,world".sout 就等于下面的内容
        System.out.println("hello , world");
    }
}

eclipse 和 IDEA的区别:


IDEA软件的对于一些快捷键,查看setting =》 Keymap查看相应的快捷键就可以了。

IDEA软件对于快速填充的标识符修改查看等等:


2. 多线程 的概念

程序,进程,线程的概念:


>传统进程 和 多线程进程:


  • 方法区:包含静态方法
  • 堆:包含各种不同的对象。
  • 方法区和堆是一个进程一份,换句话说,该进程中的线程都要共享一个方法区和堆。
  • 虚拟机栈和程序计数器,每一个线程都会有一个虚拟机栈和程序计数器。每个线程一份。

单核CPU 和 多核CPU , 并行 和 并发 的概念!!!

3. 方式一 继承Thread 线程


3.1 继承Thread 创建线程


Java语言通过java.lang.Thread类来实现多线程的!


上图对应下面代码:
(注意:run()方法是重写Thread类后的run()方法,将此线程执行的操作声明在run()方法中)


Thread创建线程格式如下:

public class TestStart{

    /*
        多线程创建:方式一继承于Thread类
        1. 创建一个继承于Thread类的子类
        2. 重写Thread类的run()方法 --> 将此线程执行的操作声明在run()方法中
        3. 创建Thread类的子类的对象
        4. 通过此对象调用start()方法
     */
    public static void main(String[] args) {
        //new MyThread(); alt  + enter 可以自动补全声明内容
        MyThread my = new MyThread();
        //start()方法作用就是启动当前线程,调用当前线程的run()方法。
        my.start();
	
		//如下操作仍然是在main线程中执行的
        //调用玩start以后,该my线程已经开始执行,但是主线程依然向下执行!!!
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println("主线程的i:" + i);
            }
        }

        //这样就相当于my子线程执行的同时,也不影响主线程的执行。
    }


}

class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0;i<100;i++){
            if(i % 2 ==0){
                System.out.println(i);
            }
        }
    }
}

3.2 Thread方式 两个问题


问题一:我们不能通过直接调用run()方法启动线程。

如果直接调用run()方法,也仅仅是调用了该run()方法。并没有开启线程,自始至终都是main线程而已。

我们通过使用Thread.currentThread().getName()来获取当前线程的名字。

public class TestStart{

    /*
        多线程创建:方式一继承于Thread类
        1. 创建一个继承于Thread类的子类
        2. 重写Thread类的run()方法 --> 将此线程执行的操作声明在run()方法中
        3. 创建Thread类的子类的对象
        4. 通过此对象调用start()方法
     */
    public static void main(String[] args) {
        //new MyThread(); alt  + enter 可以自动补全声明内容
        MyThread my = new MyThread();
        my.start();

        //调用玩start以后,该my线程已经开始执行,但是主线程依然向下执行!!!
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }

        //这样就相当于my子线程执行的同时,也不影响主线程的执行。
    }

}

class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0;i<100;i++){
            if(i % 2 ==0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}


问题二:再启动一个相同的线程,会怎么样?

会抛出异常!

其实注释中就有介绍:Throws:
IllegalThreadStateException – if the thread was already started.


因此,我们不能同时调用相同的线程,而是定义不同的对象调用不同的线程。

3.3 Thread匿名对象创建线程


匿名对象调用线程:

package com.holmes.java;

public class ThreadDemo {
    public static void main(String[] args) {
    
        //匿名对象也可以用来调用多线程
        new Thread(){
            @Override
            public void run(){
                for (int i=0;i<100;i++){
                    if (i % 2 == 0)
                        System.out.println(Thread.currentThread().getName());
                }
            }
        }.start();
    }
}

3.4 Thread类常用的方法


Thread类常用的方法:



设置线程名称两种方式:

  • 自己setName()方法设置线程名字。
  • 通过继承父类构造器方法来设置线程名字。


注意的是:因为像sleep,join等等方法都是抛出异常的,因此我们要设置throws或try-catch异常!

此外,再说一点异常范围问题,子类的异常范围一定小于父类的范围异常!!

package com.holmes.java;
    /*
        1. start()方法:启动当前线程;调用当前线程的run()方法。
        2. run()方法:重写此方法,将创建的线程要执行的操作声明在此方法中。
        3. currentThread()方法:静态方法,返回执行当前代码的线程,就是当前创建的线程对象。
        4. getName()方法:获取当前线程的名字。
        5. setName()方法: 设置当前线程的名字。
        6. yield()方法: 释放当前CPU的执行权,当然有可能下一刻又分配到当前的线程。
        7. join()方法: 在线程a中调用线程b的join()方法,此时的线程a就进入阻塞状态,直到线程b完全执行完以后线程a才结束阻塞状态,
                       再往后就看系统怎么分配资源了。
        8. stop()方法:已过时,当执行此方法时,强制结束当前线程。
        9. sleep(long millitime)方法:让当前线程“睡眠,也就是阻塞”指定的millitime毫秒(在睡眠的时间,线程是阻塞状态)。
        10. isAlive()方法: 判断当前线程是否存活。
     */
public class ThreadMethodTest {
    public static void main(String[] args) {

        //第一种:通过构造器传递String参数来命名,这在Thread源码中是具备的!
        ThreadMethods tm = new ThreadMethods("线程一");

        //第二种:可以自己给tm线程重新命名
        //tm.setName("线程一");
        tm.start();

        //怎样给主线程命名呢?
        //直接通过Thread.currentThread().setName("XXX")设置就可以了
        Thread.currentThread().setName("主线程");
        for (int i=0;i<100;i++){
            if (i % 2 == 0)
                System.out.println(Thread.currentThread().getName() + ":" +i);
            if (i == 20){
                try {
                    //join()方法使当前线程进入阻塞状态,等待另一个线程调用结束,再进行。
                    tm.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //判断tm线程是否还存在
        System.out.println(tm.isAlive());
    }
}

class ThreadMethods extends Thread{
    @Override
    public void run(){
        for (int i=0;i<100;i++){
            if (i % 2 == 0){

                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

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

            }
            //if(i % 20 == 0){
                //释放当前CPU的执行权,当然有可能下一刻又分配到当前的线程
                //yield();
            //}
        }
    }

    public ThreadMethods(String name){
        //通过继承Thread的构造器方法,来命名线程名字
        super(name);
    }
}

3.5 线程的调度



线程优先级:

  • MAX_PRIORITY :10
  • MIN_PRIORITY :1
  • NORM_PRIORITY :5


如何获取和设置当前线程的优先级:

  • getPriority() :获取线程的优先级。
  • setPriority(int p) :设置线程的优先级。

注意:高优先级的线程要抢占低优先级线程cpu执行权,但是只是从概率上来讲,并不是从一开始只有当高优先级线程执行完以后再执行低优先级。

package com.holmes.java;

public class ThreadMethodTest {
    public static void main(String[] args) {

        ThreadMethods tm = new ThreadMethods("线程一");

        //设置线程优先级
        tm.setPriority(Thread.MAX_PRIORITY);
        tm.start();

        //怎样给主线程命名呢?
        //直接通过Thread.currentThread().setName("XXX")设置就可以了
        Thread.currentThread().setName("主线程");
        for (int i=0;i<100;i++){
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() +"--"+ i);
            }
            if (i == 20){
                try {
                    //join()方法使当前线程进入阻塞状态,等待另一个线程调用结束,再进行。
                    tm.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //判断tm线程是否还存在
        System.out.println(tm.isAlive());
    }
}

class ThreadMethods extends Thread{
    @Override
    public void run(){
        for (int i=0;i<100;i++){
            if (i % 2 == 0){

                //getPriority()获取线程优先级,提示这里不写TThread.currentThread(),默认就是当前的this,还是该线程。
                System.out.println(Thread.currentThread().getName() + ":" + getPriority() + "--"+i);

            }
        }
    }

    public ThreadMethods(String name){
        //通过继承Thread的构造器方法,来命名线程名字
        super(name);
    }
}

4. 方式二 实现Runnable接口 创建多线程

package com.holmes.java;
    /*
        创建多线程方式二:实现Runnable接口
        1. 创建一个实现了Runnable接口的类。
        2. 实现类去实现Runnable中的抽象方法:run()方法。
        3. 创建实现类的对象。
        4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象。
        5. 通过Thread类的对象调用start()方法。
     */
public class ThreadTest2 {
        public static void main(String[] args) {

            MyThead3 mt3 = new MyThead3();

            //将实现类对象作为参数传递给Thread构造器
            //整体上而言就是一个多态的效果
            Thread th1 = new Thread(mt3);

            //此时这个线程是th1,而不是mt3!
            //而这里的start()方法:开启线程调用run()方法,这里的run()方法自然也是Thread中的run()方法。
            //之所以还是执行的MyThread3得看源码,如下面图:
            th1.setName("线程一");
            th1.start();

            Thread th2 = new Thread(mt3);
            th2.setName("线程二");
            th2.start();

        }
}

class MyThead3 implements Runnable{

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            if (i%2==0){
                System.out.println(Thread.currentThread().getName() +":"+ i);
            }
        }
    }
}

start()方法:开启线程调用run()方法,这里的run()方法自然也是Thread中的run()方法。

问题来了,既然是Thread中得run()方法,为什么最后还是调用得实现类MyThread中的run()方法呢?看源码。

5. 两种创建多线程方式的 对比

  • 首先,一个继承,一个实现接口。

为什么开发中,优先选择:实现Runable接口的方式?

  • 实现的方式没有类的单继承性的局限性。
  • 实现的方式更适合来处理多个线程有共享数据的情况。

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

通过看Thread源码,差不多也都知道,它们的联系。

6. JVM 和 进程线程关系




线程分为两种:一种守护线程,一种用户线程。

通过调用thread.setDaemon(true),可以将用户线程变成一个守护线程:

7. 线程的 生命周期


Thread.State类定义了线程的几种状态:

新建,就绪,运行,阻塞,死亡


生命周期流程如下:

8. 线程的 安全问题


出现线程安全的关键所在,就是多线程是否存在共享数据。


线程的安全问题:

package com.holmes.java02;

public class WindowTest2 {
    public static void main(String[] args) {

        MyThread4 m = new MyThread4();

        Thread t1 = new Thread(m);
        Thread t2 = new Thread(m);
        Thread t3 = new Thread(m);

        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        t1.start();
        t2.start();
        t3.start();
    }
}

class MyThread4 implements Runnable{

    private static int ticket = 100;

    @Override
    public void run() {
        while (true){
            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread()以上是关于Java 基础知识点 笔记总结 的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA 反射 基础知识/编码经验的一些总结

关于JAVA 异常 基础知识/编码经验的一些总结

关于JAVA 反射 基础知识/编码经验的一些总结

关于JAVA 异常 基础知识/编码经验的一些总结

Java 基础知识点 笔记总结

Java 基础知识点 笔记总结