1. 有几种新启线程的方式?
答案只有两种。我们来看看Thread的构造方法的形式,如下:
分析:
方式一:查看Thread的构造函数一类型如下:
class Thread implements Runnable {} // 线程Thread实现了接口,即里面肯定自己已经实现run方法。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0); //第二个参数Runnale对象传入的为空
}
Thread.java 中的run 如下:
public void run() {
if (target != null) {
target.run();
}
}
当调用无入参的Thread构造函数的时候,需要复写里面的run方法。
方式二,给Thread传一个Runnable对象,或者实现了Runnable接口的对象例如:FutureTask类型的对象
public Thread(Runnable target) { //其中的target,就是使用者必须要传入的 init(null, target, "Thread-" + nextThreadNum(), 0); }
注意:Thread.java中的run方法不就是一种回掉吗?
线程总共有6种状态。
1. 当线程的时间片用完了,或者被剥夺了,线程就会从运行态切换到就绪状态。
2.使用显示锁Lock, Lock的底层是使用的是park()函数,这样线程处于的状态是等待或者等待超时状态,有且仅有synchronized的时候才是阻塞状态。等待是主动行为,阻塞是被动行为。
下面是通过thread.getstate()获取的线程在虚拟机中源码定义的状态,非线程在操作系统中的状态。
注意:
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
产生死锁的条件:
1. 互斥条件。 资源独享 2. 请求和保持 3.资源不能被剥夺 4.环路等待
破锁方法:
1.强制改变拿资源的顺序。
2.拿到资源放手。 Lock接口就是这个作用。尝试拿锁。ReentrantLock
3. 复制资源,ThreadLocals 每个线程都独享资源。
在使用Lock的时候要避免出现活锁的现象,就是两个线程一个都是尝试,不断的尝试来耗费资源。这个时候就需要sleep一个随机数,等待一下让另一个线程可以有机会拿到自己的资源。sleep状态是不会释放锁的,所以需要将sleep放置在拿锁之外。
ThreadLocal学习。
如果这样处理: 做一个map, key :使用当前的线程,value存放值,这样线程是不再去争夺value资源了,但是会产生Map集合的竞争,这样又会出现不必需要的资源竞争。
出于这个原因,JDK 设计思想是:
每个线程里面都含有一个 ThreadLocalMap ,这个是Thread线程里面的私有变量,
可以通过获取当前线程来获取这个Map的。这个Map的key是当前的ThreadLocal Value为设置的值。
2. 每个map里面再存放一个Entry[]数组,这个数组里面存放的都是一个个Entry对象,这个对象里面存放是的key:ThreadLocal ,Value是设置的值。
定义在类里面的static的类和外面的类是没有任何关系的,不会持有外部类的对象。完全相互独立。
CAS(Compare and swap)
什么是原子操作?
里面的操作要不全部一起执行,要不全部都不执行。这就是原子操作。
CAS原理:自己线程拿着值去比较,如果和自己拿的值一样的,就进行相关操作,如果不是,就拿着新值重新计算再来一次。
synchronized包含的一大坨操作全部都是原子操作,不可拆分。但是这个是重量级锁。
悲观锁:先拿锁,再操作。Lock和synchronized都是悲观锁。上下文切换耗时。
乐观锁: 拿到资源就比较重试比较,这种性能比悲观锁要好。
CAS 的缺点:
1.ABA原则 使用AtomicMarkableReference AtomicStampedReference实现版本戳来解决ABA问题,每修改一次,就改一次版本。
2开销问题
Jdk中相关原子操作类的使用
更新基本类型类:AtomicBoolean,AtomicInteger,AtomicLong
更新数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
更新引用类型:AtomicReference,AtomicMarkableReference,AtomicStampedReference