如果一个类可以安全地被多个线程使用,它就是线程安全的。你无法对此论述提出任何争议,但也无法从中得到更多有意义的帮助。那么我们如何辨别线程安全与非线程安全的类?我们甚至又该如何理解“安全”呢?任何一个合理的“线程安全性”定义,其关键在于“正确性”的概念。在<
线程从创建到销毁期间有六种状态:
//线程名字,通过构造参数来指定
private char name[];
//表示线程的优先级,优先级越高,越优先被执行(最大值为10,最小值为1,默认值为5)
private int priority;
private Thread threadQ;
private long eetop;
/* Whether or not to single_step this thread. */
private boolean single_step;
//线程是否是守护线程:当所有非守护进程结束或死亡后,程序将停止
private boolean daemon = false;
/* JVM state */
private boolean stillborn = false;
//将要执行的任务
private Runnable target;
/* 线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。 */
private ThreadGroup group;
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
/*第几个线程,在init初始化线程的时候用来赋给thread.name */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* The requested stack size for this thread, or 0 if the creator did
* not specify a stack size. It is up to the VM to do whatever it
* likes with this number; some VMs will ignore it.
*/
private long stackSize;
/*
* JVM-private state that persists after native thread termination.
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/
private long tid;
/* For generating thread ID */
private static long threadSeqNumber;
/*
*线程从创建到最终的消亡,要经历若干个状态。
*一般来说,线程包括以下这几个状态:创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。
*
*/
private volatile int threadStatus = 0;
//启动新创建的线程
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".
*/
/*这个方法不会被主线程调用或通过虚拟机系统线程组创建起来。未来任何添加到该方法里的新功能可能需要加入到虚拟机中
*
* 状态new的值是0.
* */
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
/* 通知线程组新线程将要启动,以便它可以添加到线程组列表并且线程组没有开始计数*/
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
public void run() {
if (target != null) {
target.run();
}
}
package com.game.thread;
/**
*
* @author liulongling
*
*/
public class ThreadTest extends Thread{
public ThreadTest(String name) {
super.setName(name);
}
@Override
public void run() {
for(int i = 0; i < 5;i++)
{
System.out.println(super.getName()+":"+i);
}
}
public static void main(String[] args) {
ThreadTest test = new ThreadTest("A");
ThreadTest test1 = new ThreadTest("B");
test.run();
test1.run();
if(Thread.activeCount()>=1)
{
Thread.yield();
}
}
}
控制台: +------------------------------------------------------------------+
A:0 A:1 A:2 A:3 A:4 B:0 B:1 B:2 B:3 B:4
+------------------------------------------------------------------+package com.game.thread;
/**
*
* @author liulongling
*
*/
public class ThreadTest extends Thread{
public ThreadTest(String name) {
super.setName(name);
}
@Override
public void run() {
for(int i = 0; i < 5;i++)
{
System.out.println(super.getName()+":"+i);
}
}
public static void main(String[] args) {
ThreadTest test = new ThreadTest("A");
ThreadTest test1 = new ThreadTest("B");
test.start();
test1.start();
if(Thread.activeCount()>=1)
{
Thread.yield();
}
}
}
控制台: +------------------------------------------------------------------+
B:0 A:0 B:1 A:1 B:2 A:2 B:3 A:3 B:4 A:4
+------------------------------------------------------------------+ public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
private native void setPriority0(int newPriority);
setPriority使用了native关键字,在Java API中,一个native方法意味着这个方法没有使用Java语言实现,只能通过代码示例去分析它的原理。在代码中将线程A的执行优先级设置为最高,同时线程B的优先级设置为最低,那么预期的结果应该是线程A先执行完后再执行线程B,代码如下:package com.game.thread;
/**
*
* @author liulongling
*
*/
public class ThreadTest extends Thread{
public ThreadTest(String name) {
super.setName(name);
}
@Override
public void run() {
for(int i = 0; i < 5;i++)
{
System.out.println(super.getName()+":"+i);
}
}
public static void main(String[] args) {
ThreadTest test = new ThreadTest("A");
ThreadTest test1 = new ThreadTest("B");
//MAX_PRIORITY是最高优先级
test.setPriority(MAX_PRIORITY);
test.setPriority(MIN_PRIORITY);
test.start();
test1.start();
if(Thread.activeCount()>=1)
{
Thread.yield();
}
}
}
控制台: +------------------------------------------------------------------+ A:0 A:1 A:2 A:3 A:4 B:0 B:1 B:2 B:3 B:4 +------------------------------------------------------------------+
public static native void sleep(long millis) throws InterruptedException;
sleep也是使用了native关键字,调用了底层方法。sleep是指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入。多线程下使用时需要注意的是sleep方法不会释放锁。比如:线程A和线程B执行一段加锁代码,线程A先进去,线程B在外面等待,其中代码程序有sleep方法让线程休眠,休眠后锁并不会被释放,线程B也只能继续在外面等待直到休眠时间结束。代码如下:
package com.game.thread;
import java.io.IOException;
/**
*
* @author liulongling
*
*/
public class ThreadTest{
private int i = 10;
private Object object = new Object();
MyThread thread1 = new MyThread("A");
MyThread thread2 = new MyThread("B");
public static void main(String[] args) throws IOException {
ThreadTest test = new ThreadTest();
test.thread1.start();
test.thread2.start();
}
class MyThread extends Thread{
public MyThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName()+":"+i++);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
控制台: +------------------------------------------------------------------+
A:10
线程A进入睡眠状态
线程A被唤醒
A:11
B:11
线程B进入睡眠状态
线程B被唤醒
B:12
+------------------------------------------------------------------+注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return true
if this thread is alive;
* false
otherwise.
*/
public final native boolean isAlive();
表示线程当前是否为可用状态,如果线程已经启动,并且当前没有任何异常的话,则返回true,否则为false
//立即阻塞调用线程,直到该线程执行结束
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
//线程状态正常
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
package com.game.thread;
import java.io.IOException;
/**
*
* @author liulongling
*
*/
public class ThreadTest{
private int i = 10;
private Object object = new Object();
MyThread thread1 = new MyThread("A");
MyThread thread2 = new MyThread("B");
public static void main(String[] args) throws IOException {
ThreadTest test = new ThreadTest();
test.thread1.start();
System.out.println("线程"+Thread.currentThread().getName()+"等待");
try {
test.thread1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"执行");
for (int j = 0; j < 5; j++)
{
System.out.println(Thread.currentThread().getName() + ":" + j);
}
}
class MyThread extends Thread{
public MyThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName()+":"+i++);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
控制台: +------------------------------------------------------------------+
线程main等待
A:10
线程A进入睡眠状态
线程A被唤醒
A:11
线程main执行
main:0
main:1
main:2
main:3
main:4
MSDN上解释join无参方法其作用为:阻塞 “调用线程” 直到某个线程结束。从上面结果可以分析出,A线程其实在main线程上运行,我们可以说main线程调用了A线程或称main线程为“调用线程”,A线程调用join()方法后将调用线程阻塞直到A线程结束后控制台才输出来main:0...。我们去掉join方法看下控制台输出结果。控制台: +------------------------------------------------------------------+
main:0
main:1
A:10
main:2
线程A进入睡眠状态
main:3
main:4
线程A被唤醒
A:11
+------------------------------------------------------------------+join(long millis)的参数作用是指定“调用线程”的最大阻塞时间。代码如下:
package com.game.thread;
import java.io.IOException;
/**
*
* @author liulongling
*
*/
public class ThreadTest{
private int i = 10;
private Object object = new Object();
MyThread thread1 = new MyThread("A");
MyThread thread2 = new MyThread("B");
public static void main(String[] args) throws IOException {
ThreadTest test = new ThreadTest();
test.thread1.start();
System.out.println("线程"+Thread.currentThread().getName()+"等待");
try {
test.thread1.join(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"执行");
for (int j = 0; j < 5; j++)
{
System.out.println(Thread.currentThread().getName() + ":" + j);
}
}
class MyThread extends Thread{
public MyThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName()+":"+i++);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
线程main等待
A:10
线程A进入睡眠状态
线程main执行
main:0
main:1
main:2
main:3
main:4
线程A被唤醒
A:11
+------------------------------------------------------------------+ 从上面结果可以分析出,在A线程还未结束,主线程已经开始执行。原因是我们给主线程设置的阻塞时间是500ms,小于A线程run()方法里的1000ms休眠时间。interrupt的作用是中断正被阻塞的线程,比如我给某一线程休眠了10s时间,如果我在这个线程上调用了interrupt方法,看看会有什么效果。代码如下:
package com.game.thread;
import java.io.IOException;
/**
*
* @author liulongling
*
*/
public class ThreadTest{
private int i = 10;
private Object object = new Object();
MyThread thread1 = new MyThread("A");
MyThread thread2 = new MyThread("B");
public static void main(String[] args) throws IOException {
ThreadTest test = new ThreadTest();
test.thread1.start();
test.thread1.interrupt();
}
class MyThread extends Thread{
public MyThread(String name) {
super.setName(name);
}
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName()+":"+i++);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
System.out.println("你被中断了");
}
System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
控制台: +------------------------------------------------------------------+
A:10
线程A进入睡眠状态
你被中断了
线程A被唤醒
A:11 +------------------------------------------------------------------+
使用了 interrupt的结果是在休眠代码处抛出一个异常,并且阻塞马上停止了。
参考资料
http://www.cnblogs.com/dolphin0520/p/3920357.html