线程安全的几个类
函数:
isAlive():判断当前线程是否存活。
Thread.sleep是将主线程停止1秒,而不是将mythread线程停止1秒
线程安全(Thread-safe)的集合对象:
Vector 线程安全:
HashTable 线程安全:
StringBuffer 线程安全
实现多线程的方法:继承Thread类,实现Runnable 接口。
start 方法异步执行,让系统安排一个时间来调用Thread.run方法
run方法同步执行,由main的主线程调用run方法。(因此RUN方法的名字(currentThread.getName)跟main一样)
多继承是不被允许的不可以extends a.thread.但是可以 extends a implements Runnable.
thread通过init方法获取runable的target对象。
线程间共享数据问题:
解决方案1:变 量上加static,方法上加synchronized。
stackTraceElement[] getStackTrace() 返回一个表示该线程堆栈跟踪元素数组。
dumpStack( 将当前线程的堆栈跟踪消息输出至标准错误流)
static Map <Thread,StackTraceElement[]> getAllStackTraces() 返回所有活动线程的堆栈跟踪的一个映射。
getId() 获取线程的唯一标识。
interrupt() 停止线程,仅仅做一个停止标记,不立即执行。尽量不和sleep一起用。
this.interrupted()测试当前线程是否已经是中断状态,执行后具有清除状态标记值为false的功能。
this.isIterrupted()测试当前线程是否已经是中断状态,不清楚状态标志。
将interrupt()方法与return;连用。实现停止线程的效果
if(this.isInterrupted())
{ return ;
}
suspend()暂停线程,resume()恢复线程:缺点,独占,数据不完整。就是suspend把线程停住了,该有的操作,没做。
yield()放弃当前的cpu资源,让其他任务去占用CPU执行时间。,放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
setPriority()设置线程的优先级。最大是10,最小是1.
优先级可以继承,A线程启动B,则A,B线程优先级相同。
优先级高的,优先运行,但这不意味着,能优先执行完-随机性。
守护线程(垃圾回收线程),非守护线程(用户线程),当不存在非守护线程,则守护线程自动销毁。
setDaemon()设置守护线程。要在start之前执行。否则报错。
A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象的非synchronized方法。
A线程先持有object对象的lock锁,B线程如果在这时调用object对象中的synchronized类型的方法,则需要等待,也就是同步。
在方法声明处添加synchornized并不是锁方法,而是锁当前类的对象。
在java中只有“将对象作为锁”这种说法,并没有“锁方法”这种说法。
在java语言中,“锁”就是对象,对象可以映射成“锁”,哪个线程拿到这个锁·,哪个线程可以执行这个对象的synchornized同步方法。
如果在X对象中使用了synchronized关键字声明非静态方法,则X对象就被当成锁。
如果多个·方法使用了synchronized关键字声明,则这些方法在调用时使用同步调用。
synchronized锁重入:是指自己可以再次获取自己的内部锁。
锁重入也支持父子类继承的环境。子类去获取父类的锁。
重写被synchronized关键字声明的方法,如果不使用synchronized关键字声明是非同步方法,使用后变成同步方法。
public static boolean holdsLock(Object obj)方法的作用是当currentThread在指定的·对象上保存锁定时,才返回true。
当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同
步代码块在使用同步代码块的是需注意,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个
object中所有其他synchronized同步代码块的访问将被阻塞,这说明synchronized使用的对象监视器是同一个,
即使用的锁是同一个。
println()用到了同步代码块,说明执行顺序是按顺序同步的。
多个线程调用同一对象的不同名称的synchronized同步方法或synchronized(this)同步代码块,调用的效果是按顺序执行,
即同步。
synchronized同步方法的作用:
1)对其他synchronized同步方法或synchronized(this)同步代码块调用呈同步效果。
2)同一时间只有一个线程可以执行synchronized同步方法中的代码。
synchronized(this)作用:
1)对其他synchronized同步方法或synchronized(this)同步代码块调用呈同步效果。
2)同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码。
“synchronized(非this对象X)同步代码快”格式进行同步操作时,锁必须是同一个,如果不是同一个锁,则运行结果就是异步调用,交叉运行。
同步代码块放在非同步synchrod方法中进行声明,并不能保证调用方法的线程的执行同步(顺序性),也就是线程调用方法的顺序是无序的,虽然在同步块中
执行的顺序是同步的。
1)当其他线程同时执行synchronized(x){}同步代码块时呈同步效果
2)当其他线程执行x对象中synchronized同步方法时呈同步效果
3)当其他线程执行x对象里面的synchronized(this)代码块时呈现同步效果
synchronized关键字加到static静态方法上的方式是将Class对象作为锁,而synchronized关键字加到非static静态方法上的方式是
将方法所在类的对象作为锁。
synchronized(class)代码块的作用其实和synchronized static方法的作用一样。
synchronized(String) :string常量池容易使两个线程持有相同的锁。
synchronized(Object):对象不同,锁不同。
同步synchronized方法无限等待问题与解决方案----使用synchronized(Object):不同(Object):不同锁。
jps 查看线程号
jstack -l pid 查看线程
即使内置类中有两个同步方法,但使用的是不同的锁,输出结果也是异步的。
synchronized(Lock)对lock上锁后,其他线程只能以同步的方式调用lock中的同步方法。、
volatile
1)可见性:B线程能马上看到A线程更改的数据。()
2)原子性:在32位系统中,针对未使用volatile声明的long或double数据类型没有实现写原子性,如果想实现,则声明变量时添加
volatile。而在64位系统中,原子性取决于具体的实现,在X86架构64位JDK版本中,写double或long是原子的。另外,针对用volatile声明的int i变量
进行i++操作时是非原子的。
3)禁止代码重排序。
volatile当线程访问变量时,强制从公共堆栈中取值,不从私有堆栈取值,防止变量修改后还读取私有。
volatile关键字最致命的缺点是不支持原子性,也就是多个线程对用volatile修饰的变量i执行i--操作时,i--操作还会被分解成3步,造成非线程安全问题的出现。
A变量操作,B变量操作,volatile Z变量的操作,C变量的操作,D变量的操作
变量Z是一个屏障,Z变量之前或之后的代码不可以超越Z变量,这就是屏障的作用,关键字synchronized具有同样的特性。
join()方法的作用是调用线程等待该线程完成后,才能继续用下运行。
join()方法与interrupt()方法如果彼此遇到,则出现异常,不管先后顺序。
join(long)方法中的参数用于设定等待的时间,不管x线程是否执行完毕,时间到了并且重新获得了锁,则当前线程会继续向后运行。
join(long)方法的功能在内部是使用wait(long)方法来进行实验的,所以join方法具有释放锁的特点
当执行join中的wait(long)方法后当前线程的锁被释放,那么其他线程就可以调用此线程中的同步方法了。
synchronized
1)可见性
2)原子性
3)禁止代码重排序。
wait/notify(等待、通知)机制,必须是同一个锁。notify执行后并不立即释放锁,
唤醒等待同一个锁的一个线程,仅通知一个线程,唤醒的顺序与执行wait()方法的顺序一致。
notifyAll()方法执行后,会按照wait方法相反的顺序一次唤醒全部的线程。
wait等待会释放锁,sleep不会释放锁。
1)创建一个新的线程对象后,调用它的start()方法,系统会为此线程分配CPU资源,此时线程处于runnable状态,这是一个准备运行的阶段。
如果线程抢到CPU资源,则此线程就处于running状态。
running和runnable阶段可相互切换
线程进入runnable状态大体分为如下4种情况:
调用sleep()方法后经过的时间超过了指定的休眠时间。
线程成功获得了试图同步的监视器。
线程正在等待某个通知,其他线程发出了通知。
处于挂起状态的线程调用了resume恢复方法。
出现阻塞的情况大体分为如下5种:
线程调用sleep()方法,主动放弃占用的处理器资源。
线程调用了阻塞式I/O方法,在该方法返回前,该线程被阻塞。S线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有
线程等待某个通知。
程序调用了suspend()方法将线程挂起。此方法容易导致死锁,应尽量避免使用该方法。
run方法运行结束后进入销毁阶段,整个线程执行完毕。
执行完notify()方法后,按照执行wait()方法的顺序唤醒其他线程。notify()所在的同步代码块执行完才会释放对象的锁,其他
线程继续执行wait()之后的代码。
在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。
在执行同步代码块的过程中,执行了锁所属的对象的wait方法,这个线程会释放对象锁,等待被唤醒。
wait(long)等待某一时间内是否有线程对锁进行notify()通知唤醒,如果超过这个时间则线程自动唤醒,
能继续向下运行的前提是再次持有锁。
如果先通知wait()方法了。则wait方法也就没有必要执行了。
wait 与while搭配比wait与if搭配好。
while与notify可以实现几对几生产与消费的实例。
ThreadLocal的主要作用是将数据放入当前对象的map中,这个map是Thread类的实例变量。类ThreadLocal自己不管理,
不存储任何数据,用于将数据存入map中;数据--ThreadLocal--currentThread()--map
每个Thread中的map值只对当前线程可见,其他线程不可以访问当前线程对象中的map值。
继承ThreadLocal方法,重写initialValue()方法,可以修改ThreadLocal第一次调用get()方法返回值是null的情况。
使用类InhertableThreadLcoal可使子线程继承父线程的值。用不可变 到旧的数据。
当子线程继承可变对象数据类型的时候,子线程可以取到最新对象中的属性值。通过重写childVlaue()方法,子线程可以
对父线程继承的值进行加工修改。
Lock:
ReentrantLock 结合Condition类可以实现“选择性通知”,Condition对象的作用是控制并处理线程的状态,它可以使线程呈wait状态
,也可以让线程继续运行。
await()方法的作用使当前线程在接到通知或被中断之前一直处于等待wait状态。它和wait的方法作用一样。
使用await()和signal()实现wait/notify机制。
可以设置多个Condition,唤醒部分指定线程。
公平锁:采用先到先得的策略,每次获取锁之前都会检查队列里面有没有排队等待的线程,没有才会尝试获取锁,如果有就将当前
线程追加到队列里。
非公平锁:采用”有机会插队“的策略,一个线程获得锁之前要先去尝试获取锁而不是在队列中等待,如果获取锁成功,则说明线程
虽然是后启动的,但先获得了锁,这就是作弊插队的效果,如果没有成功就将当前
线程追加到队列里。
public int getHoldCount()查询当前线程保持此锁定的个数,即调用lock方法的次数。
public final int getQueueLength()返回正在等待此锁的线程估计数。
public int getWaitQueueLength(Condition condition) 方法的作用是返回等待与此锁相关的给定条件Condition的线程估计数。
public final boolean hasQueuedThread(Thread thread) 查询指定的线程是否正在等待获取此锁,也就是判断参数中的线程是否在等待队列中。
public final boolean hasQueuedThreads()是否有线程正在等待获取此锁,也就是在等待队列中是否有等待的线程。
public boolean hasWaiters(Condition condition)方法的作用是查询是否有线程正在等待与此锁有关的condition条件,也就是是否有线程执行了condition对象中
的await()方法而呈等待状态。
public final boolean isFair()方法的作用是判断是不是公平锁。在默认情况下ReentrantLock类使用的是非公平锁。
public boolean isHeldByCurrentThread()方法的使用是查询当前线程是否保持此锁。
public boolean isLocked()方法的作用是查询此锁是否由任意线程保持,并没有释放。
public void lockInterruptibly()是当某个线程尝试获得锁并且阻塞在lockInterruptibly()方法时,该线程可以被中断。、
public boolean tryLock()是嗅探拿锁,如果当前线程发现锁被其他线程持有,则返回false,程序继续执行后面的代码,而不是呈阻塞等待锁的状态。
public boolean tryLock(long timeout,TimeUnit unit)是嗅探拿锁,如果当前线程发现锁被其他线程持有,则返回false,程序继续执行后面的代码,
而不是呈阻塞等待锁的状态。如果在指定的时间timeout内持有了锁,则返回值是true,超过时间则返回false。
public boolean await(long timeout,TimeUnit unit)和public final native void wait(long timeout)一样,都具有自动唤醒线程的功能。
public long awaitNanos(long nanosTimeout)和public final native void wait(long timeout)一样,都具有自动唤醒线程的功能。
public boolean awaitUntil(Date deadline) 在指定的Date结束等待。可以在等待时间内被唤醒。
public void awaitUninterruptibly()方法的使用实现线程在等待的过程中,不允许被中断。
ReentrantLock类具有互斥排他的效果,同一时间只有一个线程在执行ReentrantLock.lock后面的方法,效率低下。
ReentrantLockReadWriteLock类不需要同步执行。
读写锁有两个锁:一个是读操作相关的锁,也称共享锁;另一个是写操作相关的锁,也称排他锁。读锁之间不互斥,
读锁与写锁互斥,写锁与写锁互斥。
schedule(TimerTask task,Date firstTime,long period)在指定日期之后按指定的间隔周期无限循环地执行某一任务。
TimerTask类中的cancel方法是将自身从任务队列中清除。
Timer类中的cancel方法是将任务队列中的全部任务清空。如果cancel没有争抢到锁,任务可能不会被停止。
schedule(TimerTask task,long delay ,long period )延迟指定的毫秒数,再以某一间隔无限次数执行某一任务。
schedule()方法和scheduleAtFixedRate()方法的主要区别在于有没有驱赶特性。
scheduleAtFixedRate()会将之前没有执行的任务,追加执行。
DCL 双检查锁。使用volatile和synchronized(object)
MyObject=new MyObject()分三个步骤
分配对象的内存空间-》初始化对象-》设置instance指向刚分配的地址。
可能会被重排序:分配对象的内存空间-》设置instance指向刚分配的地址-》初始化对象
除了DCL 还可以使用内部类。
序列化和反序列化的方式。要加上readResolve方法。
线程组:为了便于对某些具有相同功能·的线程进行管理。
一级关联:父对象有子对象。
多级关联:父对象有子对象,子对象中再创建子对象。
自动归属:自动归到当前线程组中。