首页 > 编程 > Java > 正文

【概念笔记】JAVA基础 - part3

2019-11-10 22:31:46
字体:
来源:转载
供稿:网友

java 线程和进程

进程

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

线程

线程是一个程序里面不同的执行路径

多线程: -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方法就会通知所有等待这个对象控制权的线程继续运行。

线程同步化

同步方法 即有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,但是非线程安全。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表