Java多线程——Thread类

Java 中线程实现方式有两种:

  • 继承Thread类,并重写run方法
  • 实现Runnable接口的run方法

Thread类

使用方法:继承Thread类,并重写run方法

public class Demo {
public static class MyThread extends Thread {
public void run() {
System.out.println("my thread");
}
} public static void main(String[] args) {
Thread mythread = new MyThread();
// 调用start()方法后,该线程才算启动
mythread.start();
}
}

Runable 接口

使用方法:实现Runnable接口的run方法

public class Demo1 {
public static class MyThread implements Runnable {
@Override
public void run() {
System.out.println("MyThread");
}
} public static void main(String[] args) {
new Demo.MyThread().start();
// Java 8 函数式编程,可以省略MyThread类
new Thread(() -> {
System.out.println("Java 8 匿名内部类");
}).start();
}
}

Java线程状态

Thread 类里有一个枚举类型 State,定义了线程的几种状态,分别有:

  • NEW:表示当前线程尚未启动,NEW状态表示实例化一个线程之后,但没有开始执行,即 Thread 实例还没调用 start() 方法。
  • RUNNABLE:表示当前线程正在运行中,RUNNABLE 状态包括了操作系统线程状态中的 Running 和 Ready,处于此状态的线程可能正在运行,也可能正在等待系统资源。
  • BLOCKED:表示当前线程处于阻塞状态,处于 BLOCKED 状态的线程正等待锁的释放以进入同步区。
  • WAITING:表示当前线程处于无限期等待状态,处于这种状态的线程不会被分配CPU执行时间,它们要等待显示的被其它线程唤醒。
  • TIMED_WAITING:表示当前线程处于超时等待状态,处于这种状态的线程也不会被分配 CPU 执行时间,不过无需等待被其它线程显示的唤醒,在一定时间之后它们会由系统自动的唤醒。
  • TERMINATED:表示当前线程处于终止状态,已终止线程的线程状态,线程已经结束执行,即 run() 方法执行完成。

Java8 中 state 枚举类代码:

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;
}

查看线程当前状态可以调用 getState() 方法,并进入:

/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
} // sun.misc.VM 源码:
public static State toThreadState(int var0) {
if ((var0 & 4) != 0) {
return State.RUNNABLE;
} else if ((var0 & 1024) != 0) {
return State.BLOCKED;
} else if ((var0 & 16) != 0) {
return State.WAITING;
} else if ((var0 & 32) != 0) {
return State.TIMED_WAITING;
} else if ((var0 & 2) != 0) {
return State.TERMINATED;
} else {
return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
}
}

NEW:

实例化一个线程之后,并且这个线程没有开始执行,这个时候的状态就是 NEW,尚未启动指的是还没调用 Thread 实例的 start() 方法。

关于start() 的两个引申问题:

  1. 反复调用同一个线程的start()方法是否可行?
  2. 假如一个线程执行完毕(此时处于TERMINATED状态),再次调用这个线程的start()方法是否可行?

查看 start() 方法代码:

/**
* 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(); /* 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 */
}
}
} private native void start0();

在 start() 内部,这里有一个 threadStatus 的变量。如果它不等于0,调用 start() 是会直接抛出异常的。在调用一次start()之后,threadStatus 的值会改变(threadStatus !=0),此时再次调用 start() 方法会抛出 IllegalThreadStateException 异常。

因此,两个问题的答案都是不可行。

RUNNABLE:

表示当前线程正在运行中。处于RUNNABLE状态的线程在Java虚拟机中运行,也有可能在等待其他系统资源(比如I/O)。

RUNNABLE 状态也可以理解为存活着正在尝试征用 CPU 的线程(有可能这个瞬间并没有占用CPU,但是它可能正在发送指令等待系统调度)。由于在真正的系统中,并不是开启一个线程后,CPU就只为这一个线程服务,它必须使用许多调度算法来达到某种平衡,不过这个时候线程依然处于RUNNABLE状态。

BLOCKED:

BLOCKED 称为阻塞状态,原因通常是它在等待一个“锁”,当尝试进入一个 synchronized 语句块/方法时,锁已经被其它线程占有,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的 wait() 操作后,它才有机会去争夺进入临界区的权利。

处于 BLOCKED 状态的线程,即使对其调用 thread.interrupt() 也无法改变其阻塞状态,因为 interrupt() 方法只是设置线程的中断状态,即做一个标记,不能唤醒处于阻塞状态的线程。

注意:

ReentrantLock.lock() 操作后进入的是 WAITING 状态,其内部调用的是 LockSupport.park() 方法。

WAITING:

处于这种状态的线程不会被分配CPU执行时间,它们要等待显示的被其它线程唤醒。WAITING 状态通常是指一个线程拥有对象锁后进入到相应的代码区域后,调用相应的“锁对象”的 wait() 方法操作后产生的一种结果。变相的实现还有 LockSupport.park()、Thread.join()等,它们也是在等待另一个事件的发生,也就是描述了等待的意思。

以下方法会让线程陷入无限期等待状态:

  • 没有设置timeout参数的Object.wait()

  • 没有设置timeout参数的Thread.join()

  • LockSupport.park()

注意:

LockSupport.park(Object blocker) 会挂起当前线程,参数blocker是用于设置当前线程的“volatile Object parkBlocker 成员变量”

parkBlocker 是用于记录线程是被谁阻塞的,可以通过LockSupport.getBlocker()获取到阻塞的对象,用于监控和分析线程用的。

“阻塞”与“等待”的区别:

  • “阻塞”状态是等待着获取到一个排他锁,进入“阻塞”状态都是被动的,离开“阻塞”状态是因为其它线程释放了锁,不阻塞了;

  • “等待”状态是在等待一段时间 或者 唤醒动作的发生,进入“等待”状态是主动的

如主动调用 Object.wait(),如无法获取到 ReentraantLock,主动调用 LockSupport.park(),如主线程主动调用 subThread.join(),让主线程等待子线程执行完毕再执行。离开“等待”状态是因为其它线程发生了唤醒动作或者到达了等待时间。

TIMED_WAITING:

处于这种状态的线程也不会被分配CPU执行时间,不过无需等待被其它线程显示的唤醒,在一定时间之后它们会由系统自动的唤醒。

以下方法会让线程进入TIMED_WAITING限期等待状态:

  • Thread.sleep()方法

  • 设置了timeout参数的Object.wait()方法

  • 设置了timeout参数的Thread.join()方法

  • LockSupport.parkNanos()方法

  • LockSupport.parkUntil()方法

TERMINATED:

已终止线程的线程状态,线程已经结束执行。这个状态仅仅是 Java 语言提供的一个状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求,而在Java语言级别只是通过Java代码看到的线程状态而已。

线程状态的转换

线程状态转换图:

BLOCKED状态与RUNNABLE状态的转换

处于BLOCKED状态的线程是因为在等待锁的释放。假如这里有两个线程a和b,a线程提前获得了锁并且暂未释放锁,此时b就处于BLOCKED状态。

同时,run() 方法的执行是需要时间的,并不是启动 start() 方法后就会立即执行,查看以下例子:

public class Demo2 {

    public void blockedTest() {
Thread a = new Thread(new Runnable() {
@Override
public void run() {
testMethod();
}
}, "a");
Thread b = new Thread(new Runnable() {
@Override
public void run() {
testMethod();
}
}, "b"); a.start();
b.start();
System.out.println(a.getName() + ":" + a.getState()); // 输出?
System.out.println(b.getName() + ":" + b.getState()); // 输出?
} // 同步方法争夺锁
private synchronized void testMethod() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
Demo2 demo2 = new Demo2();
demo2.blockedTest();
}
}

输出结果:此时 a 线程已得到锁,进入 run() 方法,但还没有执行 Thread.sleep(),由于 a 线程已得到锁,b 线程等待锁的释放,进入 BLOCKED 状态。

a:RUNNABLE
b:BLOCKED Process finished with exit code 0

调换语句顺序,发现结果发生变化:

public void blockedTest() throws InterruptedException {
... ...
a.start();
System.out.println(a.getName() + ":" + a.getState()); // 输出?
b.start();
System.out.println(b.getName() + ":" + b.getState()); // 输出?
}

输出结果:原因是测试方法的main线程只保证了a,b两个线程调用start()方法(转化为RUNNABLE状态),还没等两个线程真正开始争夺锁,就已经打印此时两个线程的状态(RUNNABLE)了。

a:RUNNABLE
b:RUNNABLE Process finished with exit code 0

让 main 线程停一段时间,就可以得到 BLOCKED 状态的结果:

public void blockedTest() throws InterruptedException {
... ...
a.start();
Thread.sleep(200L);
System.out.println(a.getName() + ":" + a.getState()); // 输出?
b.start();
Thread.sleep(200L);
System.out.println(b.getName() + ":" + b.getState()); // 输出?
}

输出结果:此时 a 线程已得到锁,正在执行 run() 方法,进入 TIMED_WAITING 状态,b 线程由于得不到锁,进入 BLOCKED 状态

a:TIMED_WAITING
b:BLOCKED Process finished with exit code 0

WAITING状态与RUNNABLE状态的转换

有3个方法可以使线程从RUNNABLE状态转为WAITING状态。

Thread.join():

public void blockedTest() {
······
a.start();
a.join();
b.start();
System.out.println(a.getName() + ":" + a.getState()); // 输出 TERMINATED
System.out.println(b.getName() + ":" + b.getState());
}

输出结果:调用join()方法不会释放锁,会一直等待当前线程执行完毕(转换为TERMINATED状态)。b线程的状态,有可能打印RUNNABLE(尚未进入同步方法),也有可能打印TIMED_WAITING(进入了同步方法)。

a:TERMINATED
b:TIMED_WAITING Process finished with exit code 0

需要注意的是,其他线程调用notify()方法只会唤醒单个等待锁的线程,如有有多个线程都在等待这个锁的话不一定会唤醒到之前调用wait()方法的线程。

Object.wait():导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

使用示例:

public class WaitNotifyTest {
public static void main(String[] args) {
Object lock = new Object(); new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程A等待获取lock锁");
synchronized (lock) {
try {
System.out.println("线程A获取了lock锁");
Thread.sleep(1000);
System.out.println("线程A将要运行lock.wait()方法进行等待");
lock.wait();
System.out.println("线程A等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程B等待获取lock锁");
synchronized (lock) {
System.out.println("线程B获取了lock锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B将要运行lock.notify()方法进行通知");
lock.notify();
}
}
}).start();
}
}

输出结果:

线程A等待获取lock锁
线程A获取了lock锁
线程B等待获取lock锁
线程A将要运行lock.wait()方法进行等待
线程B获取了lock锁
线程B将要运行lock.notify()方法进行通知
线程A等待结束 Process finished with exit code 0

LockSupport.park():LockSupport.park() 调用的是 Unsafe 中的 native 代码,与Object类的wait/notify机制相比,park 以 thread 为操作对象更符合阻塞线程的直观定义,操作更精准,可以准确地唤醒某一个线程增加了灵活性。

//LockSupport中
public static void park() {
UNSAFE.park(false, 0L);
}

TIMED_WAITING状态与RUNNABLE状态转换

TIMED_WAITING 与 WAITING 状态类似,只是 TIMED_WAITING 状态等待的时间是指定的。

Thread.sleep(long):

使当前线程睡眠指定时间。需要注意这里的“睡眠”只是暂时使线程停止执行,并不会释放锁。时间到后,线程会重新进入RUNNABLE状态。

Sleep 方法代码:

public static native void sleep(long millis) throws InterruptedException;

// 纳秒级别控制
public static void sleep(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
} if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
} if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
} sleep(millis);
}

Object.wait(long):

wait(long) 方法使线程进入 TIMED_WAITING 状态。这里的wait(long)方法与无参方法 wait() 相同的地方是,都可以通过其他线程调用 notify() 或 notifyAll() 方法来唤醒。

不同的地方是,有参方法 wait(long) 就算其他线程不来唤醒它,经过指定时间 long 之后它会自动唤醒,拥有去争夺锁的资格。

Thread.join(long):

join(long) 使当前线程执行指定时间,并且使线程进入 TIMED_WAITING 状态。

join(long) 的使用:调用 a.join(1000L),因为是指定了具体 a 线程执行的时间的,并且执行时间是小于 a 线程 sleep 的时间,所以 a 线程状态输出 TIMED_WAITING,b 线程状态仍然不固定(RUNNABLE 或 BLOCKED)。

public void blockedTest() {
······
a.start();
a.join(1000L);
b.start();
System.out.println(a.getName() + ":" + a.getState()); // 输出 TIEMD_WAITING
System.out.println(b.getName() + ":" + b.getState());
}

Java线程中断

Thread类里提供的关于线程中断的几个方法:

  • Thread.interrupt():中断线程。这里的中断线程并不会立即停止线程,而是设置线程的中断状态为true(默认是flase);
  • Thread.interrupted():测试当前线程是否被中断。线程的中断状态受这个方法的影响,意思是调用一次使线程中断状态设置为true,连续调用两次会使得这个线程的中断状态重新转为false;
  • Thread.isInterrupted():测试当前线程是否被中断。与上面方法不同的是调用这个方法并不会影响线程的中断状态。

“VisualVM线程监控线程状态”与“Java线程状态”对应关系总结:

通过 dump thread stack,并与 VisualVM 监控信息中的线程名称对应,找到的 VisualVM 每种线程状态的线程堆栈如下:

1、运行:RUNNABLE

"http-bio-8080-Acceptor-0" daemon prio=6 tid=0x000000000d7b4800 nid=0xa264 runnable [0x000000001197e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000c2303850> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:220)
at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers:
- None

2、休眠:sleeping

"Druid-ConnectionPool-Destory-293325558" daemon prio=6 tid=0x000000000d7ad000 nid=0x9c94 waiting on condition [0x000000000bf0f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:1685) Locked ownable synchronizers:
- None

3、等待:wait

"Finalizer" daemon prio=8 tid=0x0000000009349000 nid=0xa470 in Object.wait() [0x000000000a82f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000c22a0108> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) - locked <0x00000000c22a0108> (a java.lang.ref.ReferenceQueue.Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) Locked ownable synchronizers:
- None "JMX server connection timeout 45" daemon prio=6 tid=0x000000000e846000 nid=0xab10 in Object.wait() [0x00000000137df000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000c55da3f0> (a [I)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x00000000c55da3f0> (a [I)
at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers:
- None

4、驻留:park

"http-bio-8080-exec-2" daemon prio=6 tid=0x000000000d7b8000 nid=0x9264 waiting on condition [0x000000000ee4e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c5629bc8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor.Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread.WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers:
- None "pool-9-thread-1" prio=6 tid=0x000000000d7b2000 nid=0xd5fc waiting on condition [0x000000001187e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c563b9e0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
at java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
at java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor.Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers:
- None

5、监视:monitor

"Thread-1" prio=6 tid=0x000000000a8a1800 nid=0xfdb4 waiting for monitor entry [0x000000000b4de000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.Test2$T.run(Test2.java:58)
- waiting to lock <0x00000000eab757e0> (a java.lang.Object) Locked ownable synchronizers:
- None

汇总如下图所示:

Java多线程——Thread类的更多相关文章

  1. 探Java多线程Thread类和Runnable接口之间的联系

    首先复习一下Java多线程实现机制,Java实现多线程方法有如下这么几种: 1.继承了(extends)Thread类 2.实现了(implements)Runnable接口 也就是说  有如下两种情 ...

  2. Java多线程Thread类了解和使用

    创建线程的两种方式 extends Thread 类 public class WelComeApp { public static void main(String[] args) { Welcom ...

  3. Java并发--Thread类详情

    以下是本文的目录大纲: 一.线程的状态 二.上下文切换 三.Thread类中的方法 转载原文链接:http://www.cnblogs.com/dolphin0520/p/3920357.html 一 ...

  4. Java 线程--继承java.lang.Thread类实现线程

    现实生活中的很多事情是同时进行的,Java中为了模拟这种状态,引入了线程机制.先来看线程的基本概念. 线程是指进程中的一个执行场景,也就是执行流程,进程和线程的区别: 1.每个进程是一个应用程序,都有 ...

  5. java.lang.Thread类详解

    java.lang.Thread类详解 一.前言 位于java.lang包下的Thread类是非常重要的线程类,它实现了Runnable接口,今天我们来学习一下Thread类,在学习Thread类之前 ...

  6. Java多线程——ThreadLocal类的原理和使用

    Java多线程——ThreadLocal类的原理和使用 摘要:本文主要学习了ThreadLocal类的原理和使用. 概述 是什么 ThreadLocal可以用来维护一个变量,提供了一个ThreadLo ...

  7. 2.匿名类,匿名类对象,private/protected/public关键字、abstract抽象类,抽象方法、final关键字的使用,多线程Thread类start方法原理

    package com.bawei.multithread; //注意:模板方法我们通常使用抽象类或者抽象方法!这里我们为了方便在本类中使用就没有使用抽象类/抽象方法 public class Tem ...

  8. java多线程系类:JUC线程池:02之线程池原理(一)

    在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...

  9. java多线程系类:JUC线程池:01之线程池架构

    概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容--线程池.内容包括:线程池架构 ...

  10. java多线程系类:JUC锁:01之框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--"JUC锁"01之 框架02. Java多线程系列--"JUC锁&q ...

随机推荐

  1. K Smallest In Unsorted Array

    Find the K smallest numbers in an unsorted integer array A. The returned numbers should be in ascend ...

  2. Zabbix 监控服务介绍

    Zabbix 监控服务介绍 目录 Zabbix 监控服务介绍 一.Zabbix 监控服务介绍 1.1.1 Zabbix 监控服务介绍 1.1.2 如何去做监控 1.13 硬件监控 1.1.4 系统监控 ...

  3. 【PTA】1049 Counting Ones

    The task is simple: given any positive integer N, you are supposed to count the total number of 1's ...

  4. vue el-tree 单选实现

    <el-tree :props="props" ref="treeList" :load="loadNode" check-stric ...

  5. linux 离线安装mysql 配置开机自启动

    系统版本:centos7.8 | mysql版本:5.7.35 安装配置mysql数据库 mysql数据库配置开机自启动 1. 安装配置mysql数据库 mysql版本:5.7.35 点击下载 提取码 ...

  6. node.js 数据模拟

    Node: js在服务端的一个运行环境 node框架:express  koa  egg (本文采用express) express: 是基于node的一个web框架 restful api:是目前流 ...

  7. django中使用autocomplete无效查错

    检查autocomplete是否工作正常,将自己的结果集注释掉,使用前端预设好的结果集var countries=["Afghanistan","Albania" ...

  8. 持续集成环境(2)-Jenkins插件管理

    Jenkins本身不提供很多功能,我们可以通过使用插件来满足我们的使用.例如从Gitlab拉取代码,使用 Maven构建项目等功能需要依靠插件完成.接下来演示如何下载插件. 修改Jenkins插件下载 ...

  9. XML的定义以及XML的编写

     什么是XML? 定义 1. XML 是 EXtensible Markup Language 这个单词的简写,中文意思就是:可扩展标记语言. a)可扩展:html 标签是预先定义好的,不能任意定义, ...

  10. H. Permutation Counting 判环,计数,拓扑

    H. Permutation Counting 2022/7/28 传送门:https://codeforces.com/group/5zHJ4CTyoU/contest/392060/problem ...