基于jdk1.8
线程设置
使用多线程时,想查看线程名
Thread.currentThread().getName()
如果什么设置都没做,主线程叫main,其他线程叫Thread-*
不适用如何参数进行创建线程时,
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
nextThreadNum():
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
基于threadInitNumber:线程初始化的数量
线程初始化代码
/**
* Initializes a Thread.
*
* @param g the Thread group
* @param target the object whose run() method gets called
* @param name the name of the new Thread
* @param stackSize the desired stack size for the new thread, or
* zero to indicate that this parameter is to be ignored.
* @param acc the AccessControlContext to inherit, or
* AccessController.getContext() if null
* @param inheritThreadLocals if {@code true}, inherit initial values for
* inheritable thread-locals from the constructing thread
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
测试
实现Runnable的方式实现多线程
public class MyThread implements Runnable {
@Override
public void run() {
// 打印出当前线程的名字
System.out.println(Thread.currentThread().getName());
}
}
-- main类
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//带参构造方法给线程起名字
Thread thread1 = new Thread(myThread, "ndb");
Thread thread2 = new Thread(myThread, "lalala");
thread1.start();
thread2.start();
// 打印当前线程的名字
System.out.println(Thread.currentThread().getName());
}
}
可以通过**setName(String name)**来修改线程的名字
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);
}
}
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
public void checkAccess(Thread t) {
if (t == null) {
throw new NullPointerException("thread can't be null");
}
if (t.getThreadGroup() == rootGroup) {
checkPermission(SecurityConstants.MODIFY_THREAD_PERMISSION);
} else {
// just return
}
}
守护线程
特点:
- 为其他线程服务(垃圾回收线程就是守护线程)
- 当别的用户线程执行完,虚拟机退出,守护线程就会停止
- 属于服务线程,没有服务对象,就没必要继续运行
注意点:
- 在线程启动之前设置守护线程,setDaemon(boolean on)
- 在使用守护线程时不要访问共享资源,如数据库、文件什么的,它可能在任何时候挂掉
- 守护线程中产生的新线程也是守护线程
优先级
线程的优先级高低表示线程获取cpu时间片的几率,这个几率是,不确定因素
线程的优先级依赖于操作系统
在Java中提供10个不同的优先级,默认5级
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
实现
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);
}
}
- 如果存在线程组,那么该线程的优先级不能线程组高,如果比线程组高,该线程的优先级为线程组的最大优先级
- setPriority0是一个本地(navite)的方法,natnaive修饰的方法不由Java实现,使用c/c++实现
private natnaive void setPriority0(int newPriority);
线程的生命周期
sleep
调用sleep方法会计时等待,等待时间到,进入就绪状态而非运行状态
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
- 受精确的时间限制(单位毫秒)
yield方法
调用yield方法先让别的线程执行,但不确保真正让出(我有空,可以的话,可以让你们先执行)
/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static native void yield();
join方法
调用join方法,会等待该线程执行完毕后才能执行别的线程
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
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;
}
}
}
wait方法是在Object上定义的,是native本地方法,所以就看不了了
wait方法实际是它也是计时等待(如果带时间参数)的一种
interrupt方法
线程中断在之前的版本有stop方法,但是被设置过时了。现在已经没有强制线程终止的方法
由于stop方法可以让一个线程A终止另一个线程B
- 被终止的线程会立即释放锁,这可能会让对象处于不一致的状态
- 线程A也不知道线程B什么时候能够被终止调,万一线程B还在处理运行计算阶段,线程A调用stop方法将线程B终止,那就很无辜了
总而言之,stop方法太暴力,不安全,所以被设置过时了
一般使用interrupt来请求终止线程
- 要注意的是:interrupt不会真正停止一个线程,只是告诉这个线程一个信号,它应该结束了
- Java设计者实际上是想线程自己来终止,通过上面的信号,就可以判断处理什么业务
- 具体到底中断还是继续处理什么业务应该由被通知的线程自己处理
范例代码
Thread t1 = new Thread( new Runnable(){
public void run(){
// 若未发生中断,就正常执行任务
while(!Thread.currentThread.isInterrupted()){
// 正常任务代码……
}
// 中断的处理代码……
doSomething();
}
} ).start();
再次说明:调用interrupt()并不是要真正终止掉当前线程,仅仅是设置了一个中断标志。这个中断标志可以给我们用来判断什么时候该干什么活!什么时候中断由我们自己来决定,这样就可以安全地终止线程了!
/**
* Interrupts this thread. // 中断当前线程
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown. // 只能自己调用中断的方法,不然会抛异常
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
interrupt方法不会对线程状态造成影响,它仅仅设置一个标志位
interrupt线程中断还有两个方法用于检测线程是否被中断
- interrupted()----会清除中断标志为
- isInterrupted() ----不会清除
如果阻塞线程调用interrupt方法,会抛出异常,设置标志位false,同时线程退出阻塞
范例
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
Main main = new Main();
// 创建线程并启动
Thread t = new Thread(main.runnable);
System.out.println("This is main ");
t.start();
try {
// 在 main线程睡个3秒钟
Thread.sleep(3000);
// 在mian线程中睡了3秒,因此执行新的进程
} catch (InterruptedException e) {
System.out.println("In main");
e.printStackTrace();
}
// 设置中断
t.interrupt();
}
Runnable runnable = () -> {
int i = 0;
try {
while (i < 1000) {
// 睡个半秒钟我们再执行
Thread.sleep(500);
System.out.println(i++);
}
} catch (InterruptedException e) {
// 判断该阻塞线程是否还在
System.out.println(Thread.currentThread().isAlive());
// 判断该线程的中断标志位状态
System.out.println(Thread.currentThread().isInterrupted());
System.out.println("In Runnable");
e.printStackTrace();
}
};
}