多线程
0. 线程的状态
//Thread部分源码
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 {@code Object.wait()}
* on an object is waiting for another thread to call
* {@code Object.notify()} or {@code Object.notifyAll()} on
* that object. A thread that has called {@code Thread.join()}
* 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;
}
- 线程的6个状态,即线程的生命周期。
- NEW:使用new关键字实例化Thread对象后,还没有调用start()方法
- RUNNABLE:线程处于运行状态或者处于就绪状态等待资源
- BLOCKED:堵塞,在线程调用wait()方法后等待锁对象进入或重新进入同步块/同步方法
- WAITING:等待状态,调用了不会超时的wait()、join()、park()方法,等待其他线程的执行特定的操作,如notify(),notifyAll()方法
- TIMED_WAITING:具有等待时间的等待状态,调用了有超时的 wait()、sleep()、join()、parkNanos()、parkUntil()方法
- TERMINATED:线程终止,或者正常执行完run方法后
1. 一个线程连续调用两次start(),会有什么结果?
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread=new Thread(myRunnable);
System.out.println(thread.getState()); //查看线程状态
thread.start();
System.out.println(thread.getState()); //查看线程状态
thread.start();
System.out.println(thread.getState()); //查看线程状态
}
结果
抛出
java.lang.IllegalThreadStateException
异常,也就是说线程状态出现了异常。
- 查看start()方法部分源码
public
class Thread implements Runnable {
......
/*
* Java thread status for tools, default indicates thread 'not yet started'
*/
private volatile int threadStatus;
......
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
......
一个线程被NEW出来后就是NEW新建状态,然后通过调用start()方法进入RUNNABLE就绪状态。
看到start方法的源码注释,
It is never legal to start a thread more than once
,也就是说一个线程多次调用start方法是非法的。Thread类有一个变量
threadStatus
,表示线程的状态,0表示NEW状态。在start方法里进行了一个判断,如果线程状态不等于0,说明线程状态已经不是NEW了,说明线程至少已经处于就绪状态,再次调用start方法没有意义。
结论
一个线程不能连续调用两次或两次以上的start()方法,否则会抛出java.lang.IllegalThreadStateException
异常。
2. 为什么暂停线程废弃了suspend()方法?
原因
线程在调用suspend()方法暂停后,不会释放锁对象,有可能会导致其他线程一直处于堵塞状态。
3. 为什么会”虚假唤醒“?
原因
多线程交互中可分成三个步骤:1.判断;2.干活;3.通知;
“虚假唤醒”就是因为在调用wait()方法时的判断用了if
判断,导致虚假唤醒。
处理
查看wait()在官方API文档中的描述可知:
//中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
即在线程的判断当中用while
循环做判断,不要用if
判断。
wait()、notify()和notifyAll()方法在我印象中是
Thread
线程类里面的方法,但是实际上却是在Object
类里。
4. ⑧锁问题的核心?
问题
一个线程已经在执行中,可能执行需要的时间比较长,此时另一个线程进来,那么这个后进来的线程是马上执行?还是等待第一个线程执行完成后再执行?
原因
关键字synchronized
锁的具体对象不一样。
- 普通方法加上
synchronized
,锁的是具体的对象。
两个线程操作同一个资源对象,那线程之间就有竞争关系,
两个线程操作两个不同的资源对象,那线程之间就不存在竞争关系。
- 静态方法加上
synchronized
,锁的是整个类模板对象。
多个线程操作的资源对象只要是由同一个类模板实例化的,那就有竞争关系。
- 在代码块用
synchronized
,锁的对象是synchronized(对象)
括号里的对象。
5. 使用Callable接口实现线程
写法与运行结果
public class CallableTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask(myThread);
new Thread(futureTask, "A").start();
// get方法获取返回结果,有可能会导致堵塞,还会抛出异常,使用时要放到最后
System.out.println(futureTask.get());
}
}
/**
* 与Runnable接口的不同: 1.方法不同,call/run; 2.有返回值; 3.可以抛出异常
*/
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub
System.out.println("call......");
return 1024;
}
}
注意
-
与Runnable接口的不同: 1.方法不同,call/run; 2.有返回值; 3.可以抛出异常
-
get方法获取返回结果,有可能会导致堵塞,还会抛出异常,使用时要放到最后
FutureTask部分源码
public class FutureTask<V> implements RunnableFuture<V> {
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
// state存放的是FutureTask对象的状态
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
......
/** The result to return or exception to throw from get() */
//存放返回结果
private Object outcome; // non-volatile, protected by state reads/writes
......
// VarHandle mechanics
private static final VarHandle STATE;
......
/**
* @throws CancellationException {@inheritDoc}
*/
// 根据状态判断是直接获取返回结果,还是要等待(在外表现为堵塞)
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
......
}
也就是说同一个FutureTask对象会对线程的返回结果进行一个保存,根据状态判断是NORMAL即直接返回结果,不用再次进行运算。