- 线程是不是创建的越多越好?
首先答案肯定是不是的。在计算机世界里面回答问题不要有绝对性。
原因具体为以下几点:
Thread 中的 State 枚举
public enum State {
/**
* Thread state for a thread which has not yet started.
* 尚未启动的线程的线程状态
*
* 线程新建,还未调用start方法时。列如 :Thread thread=new Thread(new MyThread());
*/
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.
* 可运行线程的线程状态。可运行的线程
* 状态在 Java 虚拟机中执行,但它可能
* 等待来自操作系统的其他资源
* 如处理器
*
* 当调用start()方法后 线程的状态
* thread.start();
*/
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>
* 具有指定等待时间的等待线程的线程状态。
* 线程由于调用其中之一而处于定时等待状态
* 具有指定正等待时间的以下方法
* 当调用了sleep、wait、join 、LockSupport.parkNanos、LockSupport.parkUntil 等方法时,线程会进入到此状态。
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
线程中 join 方法的相关状态
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
System.out.println("t2 中执行t1.join(5000l)");
t1.join(5000L); // t2 等待 t1 1.5秒
System.out.println("t2 中执行t1.join()");
t1.join();// t2 等待 t1 执行完
System.out.println("t2 执行完成!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
Thread.sleep(1000L);
System.out.println("t2 状态 "+t2.getState());
Thread.sleep(5000L);
System.out.println("t2 状态 "+t2.getState());
}
}
执行结果
t2 中执行t1.join(5000l)
t2 状态TIMED_WAITING
t2 中执行t1.join()
t2 状态WAITING
t2 执行完成!
public class SynchronizedThread {
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
synchronized (SynchronizedThread.class){
System.out.println(" t1 抢到锁");
}
});
synchronized (SynchronizedThread.class) {
t1.start();
Thread.sleep(1000L);
System.out.println("t1抢不到锁时候的状态 "+t1.getState());
}
}
}
打印结果
t1抢不到锁时候的状态 BLOCKED
t1 抢到锁
public class ThreadWait {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
Thread t1 = new Thread(() -> {
synchronized (obj) {
try {
System.out.println(" t1将wait ( 3000L)");
// wait 方法释放锁,将锁放开,此时 main 线程获取锁
obj.wait(3000L);
// wait后的代码没有直接执行
// 主线程的synchronized 方法中代码执行完毕
// 同时使用了 obj.notify() 所以代码执行顺序回到这里
System.out.println(" t1将wait()");
// 结合上面写的 执行wait 方法后,会释放锁资源,线程的执行顺序又走到了主线程中
obj.wait();
// 此时如果再次争抢到锁的话,t1的状态就是 RUNNABLE
System.out.println(" t1 执行完");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
System.out.println("main <--> t1 start() 后的状态: " + t1.getState()); // timed_waiting
Thread.sleep(1000L);
synchronized (obj) {
// 由于 在线程中使用了wait方法,线程的锁释放,主线程争抢到锁。
// 因为 wait方法中是有时间参数 所以状态是 TIMED_WAITING 如果没有时间参数的话,就是 WAITING
System.out.println("main <--> t1的状态: " + t1.getState()); // timed_waiting
// 唤醒wait()方法
obj.notify();
// 休息一秒 但是锁并未释放资源
Thread.sleep(1000L);
// ? wating ? blocked
// 如果 没有上面的 obj.notify() 代码 那么他的状态就是 TIMED_WAITING
// 为什么时TIMED_WAITING 不是 wating 因为他是定时等待
// 因为使用了唤醒,但是主线程还是在锁的状态中 所以 t1 的状态是 BLOCKED
System.out.println("main <-->sleep 1000 后 t1的状态: " + t1.getState());
}
Thread.sleep(3000L);
// 因为 t1 的线程中 使用了 没有时间参数的 wait方法所以 状态是waiting
System.out.println("main <-->sleep 3000 后 t1的状态:" + t1.getState());
// 抢到锁以后,对 对象进行 唤醒
synchronized (obj) {
obj.notify();
}
// 如果线程中 还没有执行完的话,那么此时的线程是 阻塞状态
System.out.println("main <--> obj.notify()后 t1的状态:" + t1.getState());
//t1线程执行完毕后 继续执行main 线程的代码
Thread.sleep(1000L);
System.out.println("main <--> obj.notify() 然后 sleep 1000L 后 t1的状态:" + t1.getState());
}
// 打印结果
// t1将wait ( 3000L)
//main <--> t1的状态: TIMED_WAITING
//main <-->sleep 1000 后 t1的状态: BLOCKED
// t1将wait()
//main <-->sleep 3000 后 t1的状态:WAITING
//main <--> obj.notify()后 t1的状态:BLOCKED
// t1 执行完
//main <--> obj.notify() 然后 sleep 1000L 后 t1的状态:TERMINATED
// 如果第一开始 wait() 方法没有指定时间,并且 没有唤醒的话,那么就是waiting状态
// t1将wait ()
//main <--> t1的状态: WAITING
//main <-->sleep 1000 后 t1的状态: WAITING
//main <-->sleep 3000 后 t1的状态:WAITING
//main <--> obj.notify()后 t1的状态:BLOCKED
// t1将wait()
//main <--> obj.notify() 然后 sleep 1000L 后 t1的状态:WAITING
}
public class ThreadPark {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
LockSupport.park();
});
t1.start();
Thread.sleep(2000L);
System.out.println("t1.getState() => " + t1.getState());
// t1.getState() => WAITING
// LockSupport.park() 和wait 类似都是一种 没有设置时间的线程等待 状态都是 waiting
// 需要用 LockSupport.unpark(t1) 唤醒
LockSupport.unpark(t1);
System.out.println("2000 t1.getState() => " + t1.getState());
}
}
//t1.getState() => WAITING
public class ThreadIo {
public static void main(String[] args) throws InterruptedException {
Charset charset = Charset.forName("UTF-8");
Thread t1=new Thread(()->{
try(ServerSocket socket = new ServerSocket(9001)) {
while (true) {
System.out.println(" t1 即将接收连接...");//接收连接
Socket s = socket.accept();
System.out.println(" t1接收到连接...");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream(), charset));
String mess=null;
System.out.println("t1 将接收连接的数据...");
while (StrUtil.isNotEmpty((mess = bufferedReader.readLine()))) {
System.out.println("mess => " + mess);
}
s.close();
}
} catch (IOException e) {
e.printStackTrace();
}
});
t1.start();
Thread.sleep(3000L);
System.out.println("t1的状态:" + t1.getState());
Thread.sleep( 20000L);
System.out.println("t1的状态:" +t1.getState());
}
}
// 打印结果
为什么Thread.stop() 方法被废除了。
不安全
会立刻释放所有持有的锁,会导致被保护资源不一致,使程序结果不确定
如何正确的停止线程
1.使用violate boolean变量来标识线程是否停止
2.停止线程时,需要调用停止线程的interrupt()方法,因为线程有可能在wait()或sleep(),提高停止线程的即时性
3.对于blocking IO的处理,尽量使用InterruptibleChannel来代替
blocking lO
public class InterruptDemo {
static volatile boolean flag = true;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while (flag) {
}
System.out.println(Thread.currentThread().getName() + " 执行 interrupted 的返回" + Thread.interrupted());
while (!flag) {
}
});
t1.start();
Thread.sleep(100L);
System.out.println("interrupt() 前的状态: " + t1.isInterrupted());
System.out.println("执行interrupt()");
t1.interrupt();
System.out.println("interrupt()后的状态: " + t1.isInterrupted());
System.out.println("设置f1ag=false");
flag=false;
Thread.sleep(100L);
System.out.println("从main中再次获取t1的中断状态: " + t1.isInterrupted());
flag=true;
Thread t2=new Thread(()->{
System.out.println("t2 sleep 2000L");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2中获取自己的中断状态: " + Thread.currentThread( ).isInterrupted());
});
t2.start();
Thread.sleep(100L);
System.out.println("从main中断t2 ");
t2.interrupt();
}
}
// 打印结果
//interrupt() 前的状态: false
//执行interrupt()
//interrupt()后的状态: true
//设置f1ag=false
//Thread-0 执行 interrupted 的返回true
//从main中再次获取t1的中断状态: false
//t2 sleep 2000L
//从main中断t2
//t2中获取自己的中断状态: false
//java.lang.InterruptedException: sleep interrupted
上述代码的逻辑 ,在main线程中调用了 t1.interrupt(); 方法后,在线程内部自己获取判断是否 已经是已中断
System.out.println(Thread.currentThread().getName() + " 执行 interrupted 的返回" + Thread.interrupted());
Thread.interrupted() 返回的结果是 true 。然后再次在main线程中获取 t1.isInterrupted() 发现 状态又变回了false , 说明在 线程内部的 Thread.interrupted() 方法中擦除了 线程的中断标识。 其意义是,线程内部已经收到了,线程的被中断了,下一次,其他线程又可以继续中断他了。
//t2 sleep 2000L
//从main中断t2
//t2中获取自己的中断状态: false
结合这几行输出结果 对应的代码 ,可以看到
Thread t2=new Thread(()->{
System.out.println("t2 sleep 2000L");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2中获取自己的中断状态: " + Thread.currentThread( ).isInterrupted());
});
t2.start();
Thread.sleep(100L);
System.out.println("从main中断t2 ");
t2.interrupt();
在线程中的sleep的时候,线程的状态是TIME_WAITING 或者WAITING ,此时,如果在main线程中断了线程,那么被sleep的catch 捕捉到 中断异常,那么在线程中打印Thread.currentThread( ).isInterrupted() 就会提示false;因为已经拦截到中断异常了,所以不用再去线程中设置中断标识。
总结: 如果线程是RUNABLE 状态 ,在外面设置了线程的t2.interrupt() 方法,那么在线程内部是可以获取到 isInterrupted() 等于true ,同时擦除,如果是WAITING或者TIME_WAITING 状态,调用 t2.interrupt() 方法,则会抛出中断异常且 不会获取到中断状态标识 等于 true
public class StopDemo {
public static void main(String[] args) throws InterruptedException {
final Object object=new Object();
try {
Thread t1 = new Thread(){
@Override
public void run() {
synchronized (object){
System.out.println(getName()+" 抢到锁了");
try {
sleep(3000);
} catch (InterruptedException e) {
System.out.println("sleep异常");
}
System.out.println(Thread.currentThread().getName()+" 释放锁了");
}
}
};
Thread t2= new Thread(){
@Override
public void run() {
synchronized (object){
System.out.println(getName()+" 获取到锁了 ");
}
}
};
t1.start();
Thread.sleep(100L);
t2.start();
t1.stop();
} catch (Exception e) {
System.out.println("main "+e.getMessage());
}
}
}
// 打印结果
// Thread-0 抢到锁了
// Thread-1 获取到锁了
使用上述StopDemo 代码,查看执行结果是 同时打印了两句获取到锁的语句,按照正常逻辑,应该是Thread-0 先获取锁,再释放锁,然后Thread-1 再获取锁,因为t0 直接调用了stop()方法,同时释放了所有的锁资源,所以,t2 同时抢到锁了。这也是为什么stop方法被废除的主要原因。
线程池任务数量的统计