多线程基础(一)

什么是进程
进程是操作系统中运行的一个任务(一个应用程序运行在一个进程中)
进程(process)是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。
进程中所包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问
线程只能属于一个进程,并且它只能访问该进程所拥有的资源,当操作系统创建一个进程后,该进程会自动申请一个名为主线程或首要线程的线程

进程与线程的区别
一个进程至少有一个线程。
线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看作多个独立的应用来实现进程的调度和管理以及资源分配。

线程使用的场合
线程通常用于在一个程序中需要同时完成多个任务的情况。我们可以将每个任务定义为一个线程,使得他们得以一同工作。
也可以用于在单一线程中可以完成,但是使用多线程可以更快的情况,比如下载文件。

并发原理
多个线程“同时”运行只是我们感官上的一种表现。事实上线程是并发运行的,OS将时间划分为很多时间片段(时间片),尽可能均匀分配给每一个线程,获取时间片段的线程被CPU运行,而其他线程全部等待,所以微观上是走走停停的,宏观上都在运行。这种现象叫并发,但不是绝对意义上的“同时发生”。

线程状态
在这里插入图片描述start方法用于将线程纳入线程调度,这时线程进入runnable状态,等待线程调度分配时间片段。当线程调度将时间片段分配给当前线程,该线程的run方法才开始被执行。知道线程的run方法执行完毕,线程结束,最终被回收。在线程的run方法执行期间,该线程处于走走停停

第一种创建线程的方式

  • 继承Thread类,重写run方法

第二种创建线程的方式

  • 定义线程体runnable

第三种

  • 使用匿名内部类的形式创建线程

Thread.currentThread方法
Thread的静态方法currentThread方法可以用于获取运行当前代码片段的线程
Thread current = Thread.currentThread();

获取线程信息
Thread提供了获取线程信息的相关方法:

  • long getId():返回该线程的标识符
  • String getName():返回该线程的名称
  • int getPriority():返回线程的优先级
  • Thread.state getState():获取线程的状态
  • boolean isAlive():测试线程是否处于活动状态
  • boolean isDaemon():测试线程是否为守护线程
  • boolean isInterrupted():测试线程是否已经中断

线程优先级

  • 线程的切换时由线程调度控制的,我们无法通过代码来干涉,但是我们可以通过提高线程的优先级来最大程度的改善线程获取时间片的几率。
  • 线程的优先级被划分为10级,值分别为1-10,其中1最低,10最高,线程提供了3个常量来表示最低,最高,以及默认优先级:
    -Thread.MIN_PRIORITY,
    -Thread.MAX_PRIORITY,
    -Thread.NORM_PRIORITY

void setPriority(int priority):设置线程的优先级

守护线程
守护线程与普通线程再表现上没有什么区别,我们只需要通过Thread提供的方法来设定即可:
-void serDaemon(boolean)
-当参数为true时该线程为守护线程

守护线程的特点是,当线程中只剩下守护线程时,所有守护线程强制终止。
GC就是运行在一个守护线程上的

sleep方法

  • Thread的静态方法sleep用于使当前线程进入阻塞状态:
  • static void sleep(long ms)
  • 该方法会使当前线程进入阻塞i状态指定毫秒,当阻塞指定毫秒后,当前线程会重新进入runnable状态,等待分配时间片
  • 该方法声明抛出一个InterruptException.所以在使用该方法时需要捕获这个异常。

yield方法

  • Thread的静态方法yueld:
    -static void yield()
    该方法用于使当前线程主动让出档次cpu时间片回到runnable状态,等待分配时间片

join方法
-Thread的方法join:
void join()
该方法用于等待当前线程结束
该方法声明抛出InterruptException

synchronized关键字
-多个线程并发读写同一个临界资源时会发生“线程并发安全问题”
-常见的临界资源:
多线程共享实例变量
多线程共享静态公共变量
-若想解决线程安全问题,需要将异步的操作变为同步操作。
异步操作:多线程并发的操作,相当于各干各的
同步操作:有先后顺序的操作,相当于你干完我再干。
synchronized关键字是java中的同步锁

锁机制
-java提供了一种内置的锁机制来支持原子性:
同步代码块(synchronized关键字),同步代码块包含两部分。一个作为锁的对象的引用,一个作为这个锁保护的代码块。
synchronized(同步监视器——锁对象引用:多线程必须看到的是同一个对象才具有同步效应 ){
//代码块
}
-若方法所有diamagnetic都需要同步也可以给方法直接加锁。
-每个java对象都可以用做一个实现同步的锁,线程进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而且无论是通过正常途径退出还是通过抛出异常退出都一样,获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法

如果synchronize块在一个非静态方法中,那么通常锁对象写的是this

wait和notify
-多线程之间需要协调工作
-例如,浏览器的一个显示图片的 displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。
-以上逻辑简单的就是说:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在java中,这个机制的实现依赖于wait/notify.等待机制与锁机制是密切关联的。

我们调用哪个对象的wait或notify就应当对当前方法加锁,锁对象就是当前对象

线程安全API与非线程安全API
StringBuffer是同步的 synchronized append();
StringBuilder不是同步的 append()

Vector和Hashtable是同步的
ArrayList和HashMap不是同步的

获取线程安全的集合方式
-Collections.synchronizedList()
获取线程安全的List集合
-Collections.synchronizedMap()
获取线程安全的Map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值