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. ZSTUOJ刷题12:Problem B.--深入浅出学算法007-统计求和

    Problem B: 深入浅出学算法007-统计求和 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 6782  Solved: 3693 Descript ...

  2. TFLCD编程过程中遇到的问题之.\Objects\EXTI_Project.axf: Error: L6218E: Undefined symbol POINT_COLOR (referred from tflcd.o).

    在TFLCD屏幕中遇到的问题及解决方案 1.问题提出 在对正点原子提供的有关TFLCD屏幕做移植过程中,编译过程中没有报错,但是链接时就出现了报错,报错信息如下图所示: 像这种错误,无法定义到错误所在 ...

  3. uniapp里面设置onlaunch以后在加载页面调接口

    main.js 里面 Vue.prototype.$onLaunched = new Promise(resolve => { Vue.prototype.$isResolve = resolv ...

  4. 上分准备 VP Codeforces Round #762 (Div. 3) 4题ABCE

    +00:02 +00:16 +01:08   +02:07 VP 情况  4/8 ABCE ,赛时排名可以到823,什么时候我可以上个青 B 本想写个map的二分的,发现自己不会,写了个普普通通的二分 ...

  5. 通过Linux的socket套接字实现客户端与服务器端的通信

    具体案例:使用树莓派ds18b20温度传感器实现温度上报 首先需要获得传感器文件中保存的温度信息: 温度信息通常保存在路径为"/sys/bus/w1/devices/28-xxxxxxxxx ...

  6. PLC入门笔记12

    1.边沿应用 (1)边沿开关 (2)上升沿触发 下降沿触发 (3) MOVP K4M0 D0 传送比较 movp (=mov) 脉冲型指令 前面条件成立只能执行一次,仅执行一次扫描周期 不带P MOV ...

  7. JS Math与一些原始类型

    镇楼图 Pixiv:DSマイル 一.值属性.函数 globalThis JS有全局对象,但是在不同环境中全局对象均不同.在Web环境中,window.self.frames取得全局对象,在Web Wo ...

  8. C# NAudio 检测声音

    using NAudio.Wave;using System;using System.Collections.Generic; namespace WinFromBaidu{ class NAudi ...

  9. 「进阶」缓解眼睛疲劳,防蓝光保护视力,关爱健康!- CareUEyes

    软件官网地址:https://care-eyes.com/ 显示 对于显示页面来说 8 个模式下面都有对应的介绍说明,不再介绍.笔者建议软件调节之前,先退出软件,用系统自带的亮度调节,进入电源选项中进 ...

  10. Promise 一些注意点

    Promise是一个构造函数,其身上有all.race.resolve.reject这些方法,都可以通过 Promise. 调用. 注意点1 Promise构造函数接受一个参数 => funct ...