1线程基本概念
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程
应用程序的执行实例,有独立的内存空间和系统资源。
线程
CPU调度和分派的基本单位,进程中执行运算的最小单位,可完成一个独立的顺序控制流程。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量,即方法区),扩展段(即堆存储);但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
进程与线程
1) 一个程序至少有一个进程,一个进程至少有一个线程.可以有多进程也可以有多线程。
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
2线程创建与启动
Thread类:实际上是实现了Runnable接口的类
Runnable接口
线程创建两种方法:第一种继承Thread类;第二种实现Runnable接口,作为Thread类的参数(接口回调),可以再继承其他类,创建多个对象start执行的都是同一个对象。
执行run启动start
3线程声明周期
新建-就绪-运行-(阻塞)-终止
阻塞:sleep,suspend,join,wait,synchronized锁住,
接触阻塞:resume
运行转就绪:yield
死亡:stop
4线程安全性
原因:多个线程访问出现延迟(手动sleep几秒,线程已经进入执行态但是还没有更新票数即延迟,其他线程再次进入,线程特别多时容易出现);线程随机性。
解决:同步代码块synchronized。同步的弊端:速度明显变慢了,需要等每个线程执行完。 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。所以要考虑synchronized的范围尽可能小。
同步方法:方法名(返回值)前加,默认锁this,静态修饰锁就是当前类名.class;
同步代码块:用synchronized(对象){}包起来,对象就是锁。
如果使用的锁是this,同一套数据用不同的锁时是不安全的。用static。
同步需满足的条件:
同步需要两个或者两个以上的线程;多个线程使用的是同一个锁。
饿汉式设计模式,在一开始就新建类对象;
懒汉式设计模式,在要用到对象时才创建,意味着创建对象的语句是放在一个函数内,当用多个线程使用这个单例类时且这个获取对象的函数执行出现延迟,会出现单例类执行了多条new语句,而且这还导致内存泄漏。解决:把这个函数改为同步函数(懒汉式加同步和懒汉式加高效同步)。
wait。notify,notifyAll这些操作线程的函数都定义在Object类中,因为这些方法存在在同步中,只有具体的锁才能调用他们,且锁可以是任意类的对象。
wait和sleep的区别:都是释放CPU执行权,但是wait释放锁,sleep不释放锁。
//懒汉式的单例设计模式 加同步
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s==null)
s = new Single();
return s;
}
}
//懒汉式的单例设计模式 加高效同步
请写出一个延迟加载的单例设计模式示例。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
//缩小了synchronized的范围,并且只有在s为null才判断要不要进入synchronized机制(即判断锁是否被占用,这个比if费时多了)
if(s==null)
{
synchronized(Single.class)
{if(s==null)
s = new Single();}
}
return s;
}}