线程(小结)

线程安全的几个类
函数: 
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方法。

线程组:为了便于对某些具有相同功能·的线程进行管理。

一级关联:父对象有子对象。
多级关联:父对象有子对象,子对象中再创建子对象。
自动归属:自动归到当前线程组中。

Java多线程是指在一个Java程序中同时执行多个线程,每个线程都是独立的执行流。Java中创建线程的方式有三种:继承Thread类、实现Runnable接口和实现Callable接口。每种方式都有其优缺点。 1. 继承Thread类创建线程类: ```java class MyThread extends Thread { public void run() { // 线程执行的代码 } } // 创建线程对象并启动线程 MyThread thread = new MyThread(); thread.start(); ``` 优点:简单易用,可以直接重写Thread类的run()方法。 缺点:由于Java不支持多继承,继承了Thread类就无法再继承其他类。 2. 实现Runnable接口创建线程类: ```java class MyRunnable implements Runnable { public void run() { // 线程执行的代码 } } // 创建线程对象并启动线程 Thread thread = new Thread(new MyRunnable()); thread.start(); ``` 优点:避免了单继承的限制,可以继续继承其他类或实现其他接口。 缺点:需要额外创建Thread对象,并将Runnable对象作为参数传递给Thread对象。 3. 实现Callable接口创建线程类: ```java class MyCallable implements Callable<Integer> { public Integer call() throws Exception { // 线程执行的代码 return 0; } } // 创建线程池对象 ExecutorService executor = Executors.newFixedThreadPool(1); // 提交Callable任务并获取Future对象 Future<Integer> future = executor.submit(new MyCallable()); // 获取线程执行结果 int result = future.get(); ``` 优点:可以获取线程执行的结果,并且可以抛出异常。 缺点:相对于前两种方式,使用Callable需要更多的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值