【概念笔记】JAVA基础 - part3

版权声明:本文为博主原创文章,未经博主允许不得转载。转载请附上博主博文网址,并标注作者。违者必究 https://blog.csdn.net/HuHui_/article/details/54917566

JAVA 线程和进程

进程

进程是一个静态的概念
事实上,进程在执行指的是进程里面主线程开始执行了

线程

  1. 线程是一个程序里面不同的执行路径
  2. 多线程:
    -sleep()和wait()
    这两个函数都能让在休息时间内让其他线程执行。
    sleep是线程被调用时,占着cpu去睡觉,其他线程不能占用cpu,os认为该线程正在工作,不会让出系统资源,wait是进入等待池等待,让出系统资源,其他线程可以占用cpu,一般wait不会加时间限制,因为如果wait的线程运行资源不够,再出来也没用,要等待其他线程调用notifyall方法唤醒等待池中的所有线程,才会在进入就绪序列等待os分配系统资源,
    sleep是静态方法,是谁掉的谁去睡觉,就算是在main线程里调用了线程b的sleep方法,实际上还是main去睡觉,想让线程b去睡觉要在b的代码中掉sleep
    -notify()和notifyAll()
    如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
    如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
    如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

  3. 线程同步化

    • 同步方法
      即有synchronized关键字修饰的方法。
      由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
      内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

    代码如:

    public synchronized void save(){}

注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

- 同步代码块 
即有synchronized关键字修饰的语句块。 
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

代码如: 
    synchronized(object){ 
    }
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 

代码实例: 
package com.xhj.thread;

    /**
     * 线程同步的运用
     * 
     * @author XIEHEJUN
     * 
     */
    public class SynchronizedThread {

        class Bank {

            private int account = 100;

            public int getAccount() {
                return account;
            }

            /**
             * 用同步方法实现
             * 
             * @param money
             */
            public synchronized void save(int money) {
                account += money;
            }

            /**
             * 用同步代码块实现
             * 
             * @param money
             */
            public void save1(int money) {
                synchronized (this) {
                    account += money;
                }
            }
        }

        class NewThread implements Runnable {
            private Bank bank;

            public NewThread(Bank bank) {
                this.bank = bank;
            }

            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    // bank.save1(10);
                    bank.save(10);
                    System.out.println(i + "账户余额为:" + bank.getAccount());
                }
            }

        }

        /**
         * 建立线程,调用内部类
         */
        public void useThread() {
            Bank bank = new Bank();
            NewThread new_thread = new NewThread(bank);
            System.out.println("线程1");
            Thread thread1 = new Thread(new_thread);
            thread1.start();
            System.out.println("线程2");
            Thread thread2 = new Thread(new_thread);
            thread2.start();
        }

        public static void main(String[] args) {
            SynchronizedThread st = new SynchronizedThread();
            st.useThread();
        }

    }

这里附带一篇用于理解进程和线程的,写的很好的文章,很生动! 转载:进程和线程理解

JAVA多线程

多线程的作用

1)发挥多核CPU的优势
2)防止阻塞

  • 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程,进程是资源分配的最小单位。

- 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小,线程是CPU调度的最小单位。

实现线程的方式

继承Thread或者实现Runnable接口

线程的状态

这里写图片描述
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程的优先级

Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。

注意:
不要假定高优先级的线程一定先于低优先级的线程执行,不要有逻辑依赖于线程优先级,否则可能产生意外结果。

线程的联合

Join
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

线程的同步

synchronized
1)同步方法
2)同步代码块

synchronized关键字不能被继承

死锁

线程的休眠

sleep

sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
   sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。

线程间的通信(线程协作)

wait()方法和notify()/notifyAll()方法在调用前都必须先获得对象的锁。

void notify()
唤醒在此对象监视器上等待的某一个线程.具体是哪一个可以认为是不确定的.
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.
wait会释放占有的锁,notify和notifyAll不会释放占用的锁。

用户线程和守护线程
线程池

虚拟机内存模型

模型图

类型 默认值
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char ‘\u0000’
boolean false
All reference types null

内部类

内部类是定义在其他类内部的类:
1) 内部类对象能够访问创建它的对象的实现-包括那些私有数据;
2) 内部类能够隐藏起来,不为同一包中的其他类所见;
3) 匿名内部类可以方便地定义运行时回调;
4) 所有内部类在编写事件程序时用起来很方便。
1、静态内部类
1) 内部类的最简单形式;
2) 不能和外部类同名;
3) 被编译成一个独立的类文件;
4) 只能访问外部类的静态方法、静态实例变量(包括私有类型);
5) 静态内部类创建实例的形式:外部类名.内部类名 实例名 = new外部类名.内部类名(参数),注意:在不同的包才需要加外部类名。

2、实例内部类
1) 定义在类内部,没有使用static修饰符;
2) 像实例变量;
3) 能访问外部类的所有实例变量;
4) 在一个外部类里创建一个实例内部类实例:this.new Innerclass();
5) 在一个外部类外创建一个实例内部类实例:(new OuterClass()).new Innerclass();
6) 在一个内部类里访问一个实例内部类:Outerclass.this.member;

3、局部内部类
1) 定义在方法里;
2) 最少的一种内部类;
3) 和局部变量类似, 不能被定义为public,protected,private和static;
4) 局部内部类访问外部类的属性和方法使用“外部类名.this.属性名”和“外部类名.this.方法名(参数)”的形式;
5) 只能访问final型局部变量。
6) 局部内部类只在本作用域中可见。

4、匿名内部类
1) 没有类名;
2) 没有class关键字;
3) 没有继承和声明;
4) 没有构造函数;

Object

“==”操作符和equals()方法
在自己设计的实体类中,建议覆盖equals()方法,定义自己的比较逻辑,经典写法步骤:
1、如果传入对象为null,返回false
2、如果传入对象与this地址相等返回true
3、如果类型不匹配返回false
4、类型转换后比较属性

toString()方法
1、和equals()方法一样,toString()是Object类另外一个重要的方法;
2、它返回一个代表该对象值的字符串。几乎每个类都会覆盖该方法,以便打印该对象当前状态的表示。
3、无论何时对象同字符串相连接,那么就可以使用”+”操作符,这时Java编译器会自动调用toString方法获得对象的字符串表示。(把字符串先写在前面)

String&StringBuffer& StringBuilder

java.lang.String———–>不变字符对象,对象创建后其内容不能修改,线程安全。
java.lang.StringBuffer—–>可变字符对象,对象创建后可直接在原地址上修改,线程安全。
java.lang.StringBuilder同StringBuffer,但是非线程安全。

猜你喜欢

转载自blog.csdn.net/HuHui_/article/details/54917566