Day20

一、笔记:

Collection:List  Set
Iterator:iterator()获取迭代器的对象
Map:HashMap Properties  

IO:
字节:InputStream  OutputStream
字符:Reader    Writer


文件流:FileInputStream  FileOutputStream  FileReader    FileWriter
缓冲流
转换流
打印流  
对象流

程序:硬盘中的一个可执行文件,一段静态的代码块。
进程:程序的一次执行过程,运行在内存中的程序
线程:进程中的一条执行路径。
多线程:进程中的多条执行路径。

Thread(线程):Java提供的创建线程的类


run():放入需要执行的代码
start():用来启动线程,默认调用run()。
继承Thread
1.将类声明为 Thread 的子类
2.重写 Thread 类的 run 方法
3.创建子类对象
4.使用start()启动线程

 

实现Runnable(必须掌握)
1.将类实现Runnable
2.实现run方法
3.创建Thread对象,将子实现类对象作为参数传递到Thread对象中
4.启动线程

多线程:

基本概念

程序 - 数据结构 + 算法。指的是硬盘中的一个可执行文件

进程 - 主要指运行在内存中的程序

  目前主流的操作系统都支持多进程,是为了让操作系统能够同时执行多个任务,但进程是 重量级的,新建进程对系统资源的消耗比较大,因此进程的数量是有限的。

线程 - 是进程内部的程序流,也就是说操作系统中支持多进程,而每个进程的内部又可以支持多线程,并且线程是轻量级的,新建线程会共享所在进程的资源,因此对资源消耗比较小。

  以后的主流开发都采用多线程机制,而操作系统中主要采用时间片轮转法来保证多任务的同时执行,该策略叫做并发机制,也就是宏观并行,微观串行的机制。

线程的创建(重中之重)

Thread类创建线程的方式

Thread类主要用于描述线程,Java虚拟机允许Java程序启动多个线程并同时执行

创建线程的方式:

•    a.自定义类继承Thread类并重写run()方法,然后创建自定义类的对象调用start()方法

    b.自定义类实现Runnable接口并重写run()方法,然后创建自定义类的对象作为创建Thread类对象的实参,最后使用Thread类的对象调用start()方法。

创建线程的有关方法

Thread() - 无参的方式构造对象。

Thread(String name) - 使用参数指定的名称来构造对象。

Thread(Runnable target) - 根据参数指定的引用来构造对象。

       - 其中Runnable是个接口,实参的传递方式有两种:

           a.自定义类实现Runnable接口,构造自定义类的对象作为实参传递。

           b.使用匿名内部类直接构造接口类型的引用作为实参传递。

Thread(Runnable target, String name)

       - 使用参数指定的引用和名称共同构造对象

线程创建的执行原理

   执行main()方法的线程叫做主线程,执行run()方法的线程叫做子/新线程。

   对于start()方法之前的代码来说,由主线程执行一次,当start()方法调用成功后,则线程的个数瞬间由1个变成了2个,其中新创建的子线程去执行run()方法,主线程继续执行后续代码,两个线程同时执行互不影响。

   当run()方法结束时则子线程结束,当main()方法结束时则主线程结束,两个线程执行的先后次序没有明确的规定,由系统调度算法决定。

注意:

   创建线程两种方式里面继承相对简单容易理解,但是Java语言支持单继承,若一个类继承Thread类后则无法继承其他类,因此推荐使用第二种方式来创建线程,从而提高代码的可维护性和可扩展性。

线程的编号和名称(熟悉)

•   long getId() - 用于获取调用对象的线程编号。

   String getName() - 用于获取调用对象的线程名称。

   void setName(String name) - 用于设置线程名称为参数指定数值。

   static Thread currentThread() - 用于返回当前正在执行线程对象的引用。

线程的主要状态(熟悉)(生命周期)

   新建状态 - 当使用new关键字创建线程对象之后进入的状态。

                      - 此时该线程并没有开始执行。

   就绪状态 - 当线程对象调用start()方法之后进入的状态。

                      - 此时该线程仍然没有开始执行。 

   运行状态 - 当线程对象被线程调度器调度之后进入的状态。

                      - 此时该线程开始执行。

                      - 当线程对象的时间片执行完毕但任务没有完成时回到就绪状态。

   消亡状态 - 当线程对象的时间片执行完毕并且任务已经完成后进入的状态。

   阻塞状态 - 当线程执行过程中发生阻塞事件后进入的状态,如:sleep()方法。 

                      - 当阻塞解除后进入就绪状态。

线程的常用方法

    static void sleep(long millis)

       - 用于使得当前正在执行的线程进入休眠状态,休眠参数指定的毫秒(重点)。

   int getPriority() - 用于获取调用对象的优先级并返回。

线程中的优先级:1   5   10  默认优先级为:5

Thread类中提供了三个字段表示级别:MAX_PRIORITY,  MIN_PRIORITY  ,NORM_PRIORITY

   void setPriority(int newPriority) - 用于设置调用对象的优先级。

       - 优先级越高则表示优先获取CPU时间片的机会越大,但不保证该线程一定先执行。

  

   void join() - 用于等待调用对象所表示的线程终止(重点)。

   void join(long millis) - 用于等待调用对象所表示线程终止的最长时间为参数指定毫秒

 

   boolean isDaemon() - 用于判断调用对象所表示的线程是否为守护线程。

   void setDaemon(boolean on) - 用于设置调用对象所表示线程为守护线程。

       - 该方法的调用必须在线程调用start()方法之前。

       - 当所有非守护线程结束时,则守护线程随之结束。

线程的同步机制(重点)

基本概念

   当多个线程同时访问同一种共享资源时,可能会造成数据的不一致或覆盖等问题,此时就需要对线程之间进行协调和通信,该方式就叫做线程的同步机制。

案例:取钱

解决方案

   由程序结果可知:当两个线程同时进行取款时,导致最终的账户余额不合理。

   原因:线程一还没有来得及将取款后的余额写入数据库,但线程二已经开始执行。

   解决方案:将线程的并发操作改为线程的串行操作即可。

   引发问题:该方式会造成线程执行的效率降低,因此以后的开发中能不用则不用。

实现方式  synchronized

在Java语言中可以借助synchronized关键字实现同步锁/对象锁机制,来保证线程执行的原子性,具体方式如下:

   (1)使用同步语句块的机制来实现

      synchronized(对象的引用){

          编写所有需要锁定的代码块;

      }

   (2)使用synchronized关键字修饰整个方法,表示锁定整个方法的方法体。

      该方式等价于 synchronized(this){ 方法体; }。

实现原理(尽量理解)

当多个线程启动之后同时去抢占共享资源,若其中一个线程抢到了共享资源,则其他线程进入阻塞/等待状态,直到该线程执行完毕所有锁定的代码后会自动释放对象锁,此时等待的线程又可以抢占共享资源,抢到对象锁的代码执行锁定的代码,抢不到的线程继续等待。

死锁(了解)

同步锁使用的弊端当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。

经验:

•   在以后的开发中切记不要使用同步语句块的嵌套结构!!! 

线程通信--等待唤醒机制

概念——线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。

wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。

notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。

notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。

其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。

二、巩固

package com.qfedu.zhuguangyi.thread;

public class Singleton {

	
	private  Singleton() {}
	
	private  static Singleton  sin = null;

	private static Object o = new Object();
	public static Singleton getSingleton() {
		
		synchronized (o) {
			if (sin == null) {

				try {
					Thread.currentThread().sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				sin = new Singleton();
			}
		}
		return  sin;
	}

}
package com.qfedu.zhuguangyi.thread;

public class Test extends  Thread{

	public void run() {
		
		
		Singleton singleton = Singleton.getSingleton();
		System.out.println(singleton);
	}
	
}
package com.qfedu.zhuguangyi.thread;

public class TestSin {

	public static void main(String[] args) {
		Test t = new Test();
		Test t1 = new Test();
		
		t.start();
		t1.start();
	}
}

不要轻言放弃,否则对不起自己!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值