- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
Java提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程。线程调度器通过线程的优先级来决定调度哪些线程执行。一般来说,Java的线程调度器采用时间片轮转算法使多个线程轮转获得CPU的时间片。
线程可以划分优先级,优先级高的线程得到的CPU资源比较多,也就是CPU优先执行优先级高的线程对象中的任务。优先级具有随机性,不一定优先级高的有限制性。
// 优先级
private int priority;
// 获取优先级
public final int getPriority() {
return priority;
}
// 设置优先级,java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率
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);
}
}
/**
* 线程可以具有的最低优先级
*/
public final static int MIN_PRIORITY = 1;
/**
* 分配给线程的默认优先级。
*/
public final static int NORM_PRIORITY = 5;
/**
* 线程可以具有的最大优先级。
*/
public final static int MAX_PRIORITY = 10;
public class Test001 {
public static void main(String[] args) {
MyThread001 thread001 = new MyThread001();
// 设置优先级最高
thread001.setPriority(Thread.MAX_PRIORITY);
thread001.start();
// 设置优先级最低
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
// 打印优先级
System.out.println("thread001优先级:"+thread001.getPriority());
System.out.println("Main 优先级:"+Thread.currentThread().getPriority());
System.out.println(Thread.currentThread().getName() + "线程正在运行任务");
}
}
在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemon Thread)。
用户线程:我们平常创建的普通线程。
守护线程:守护线程是一类比较特殊的线程,一般用于处理一些后台的工作,随着用户线程的销毁,守护线程也会随着销毁,比如JDK的垃圾回收线程。
守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。
Java垃圾回收线程就是一个典型的守护线程,因为我们的垃圾回收是一个一直需要运行的机制,但是当没有用户线程的时候,也就不需要垃圾回收线程了,守护线程刚好满足这样的需求。
场景:某个用户线程在执行时,需要一个定时无线循环线程,去检测心跳,一旦用户线程结束,这个检测线程也需要关闭。如果不设置守护线程,那个这个检测线程将无法停止,此时可以这只设置这个线程为守护线程,随着业务线程的完成而自动退出。
public class DaemonThreadTest001 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "正在检测心跳");
try {
Thread.sleep( 3_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"检测心跳任务线程");
// 设置为守护线程
t.setDaemon(true);
// 查看线程是否为守护线程
System.out.println(t.getName()+"是否守护线程"+t.isDaemon());
System.out.println(Thread.currentThread().getName()+"是否守护线程"+Thread.currentThread().isDaemon());
t.start();
try {
Thread.sleep( 20_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "线程任务运行结束");
}
}
1、 设置守护线程的方法很简单,调用setDaemon方法即可,true代表守护线程,false代表正常线程;
2、 线程是否为守护线程和它的父线程有很大的关系,如果父线程是正常线程,则子线程也是正常线程,反之亦然,如果你想要修改它的特性则可以借助setDaemon方法isDaemon方法可以判断该线程是不是守护线程;
3、 setDaemon(true)必须在t.start()之前设置,否则会抛出IllegalThreadStateException异常;
public long getId()获取线程的唯一ID,线程的ID在整个JVM进程中都会是唯一的。并且是从0开始逐次递增。在一个JVM进程启动的时候,实际上是开辟了很多个线程,自增序列已经有了一定的消耗,因此我们自己创建的线程可能并不是第0号线程。
// 获取线程长整型的 id,id 唯一
long id = t.getId();
public static Thread currentThread()用于返回当前执行线程的引用。
// 获取当前正在执行的线程
Thread thread = Thread.currentThread();
sleep方法方法会使当前线程进人指定毫秒数的休眠,暂停执行,虽然给定了一个休眠的时间,但是最终要以系统的定时器和调度器的精度为准,休眠有一个非常重要的特性,那就是其不会放弃监视器锁的所有权。
sleep是一个静态方法,其有两个重载方法,其中一个需要传入毫秒数,另外一个既需要毫秒数也需要纳秒数。
在JDK1.5以后,JDK引入了一个枚举TimeUnit,其对sleep方法提供了很好的封装,使用它可以省去时间单位的换算步骤。
public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
案例:
// 休眠3秒
Thread.sleep(3_000);
TimeUnit.SECONDS.sleep(3);
yield方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前的CPU资源,如果CPU的资源不紧张,则会忽略这种提醒。调用yield方法会使当前线程从RUNNING状态切换到RUNNABLE状态,一般这个方法不太常用。主要是为了测试和调试。
public static native void yield();
1、 sleep会导致当前线程暂停指定的时间,没有CPU时间片的消耗;
2、 yield只是对CPU调度器的一个提示,如果CPU调度器没有忽略这个提示,它会导致线程上下文的切换;
3、 sleep会使线程短暂block,会在给定的时间内释放CPU资源;
4、 yield会使RUNNING状态的Thread进入RUNNABLE状态(如果CPU调度器没有忽略这个提示的话);
5、 sleep几乎百分之百地完成了给定时间的休眠,而yield的提示并不能一定担保;
6、 一个线程sleep另一个线程调用interrupt会捕获到中断信号,而yield则不会;
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
return contextClassLoader;
}
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
public ClassLoader getContextClassLoader()获取线程上下文的类加载器,简单来说就是这个线程是由哪个类加器加载的,如果是在没有修改线程上下文类加载器的情况下,则保持与父线程同样的类加载器。
public void setContextClassLoader(ClassLoader cl)设置该线程的类加载器,这个方法可以打破JAVA类加载器的父委托机制,有时候该方法也被称为JAVA类加载器的后门。
取消一个任务的执行,最好的,同时也是最合理的方法,就是通过中断。
// 打断线程
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();
}
// 判断当前线程是否被打断
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
// 测试某些线程是否已被中断
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
调用sleep或wait方法时,会使得当前线程进入阻塞状态,而调用当前线程的interrupt方法,就可以打断阻塞。打断一个线程并不等于该线程的生命周期结束,仅仅是打断了当前线程的阻塞状态。一旦线程在阻塞的情况下被打断,都会抛出一个称为InterruptedException的异常。
在一个线程内部存在着名为interrupt flag的标识,如果一个线程被interrupt,那么它的flag将被设置,但是如果当前线程正在执行可中断方法被阻塞时,调用interrupt方法将其中断,反而会导致flag被清除。
wait方和sleep方法前线程被中断了会抛出InterruptedException,并且清除中断状态。但是并不会终止当前线程的执行,当前线程可以选择忽略这个异常。
无论是设置interrupt status 还是抛出InterruptedException,它们都是给当前线程的建议,当前线程可以选择采纳或者不采纳,它们并不会影响当前线程的执行。
至于在收到这些中断的建议后,当前线程要怎么处理,也完全取决于当前线程。
public class InterruptThreadTest001 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "正在检测心跳");
System.out.println("中断状态" + Thread.interrupted());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// 被中断时 退出循环
e.printStackTrace();
break;
}
}
}
}, "检测心跳任务线程");
// 获取当前线程
t.start();
try {
Thread.sleep(20_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 中断
t.interrupt();
System.out.println(Thread.currentThread().getName() + "线程任务运行结束");
}
}
在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
public final void join() throws InterruptedException
public final synchronized void join(long millis, int nanos)throws InterruptedException
public final synchronized void join(long millis)throws InterruptedException
线程t2先启动,3秒后才启动t1,但是由于t2使用了t1.jion(),则会等待t1执行完毕后,t2才会执行后续代码。
public class JoinThreadTest001 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "正在检测心跳");
}, "线程001");
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在检测心跳");
}, "线程002");
t2.start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.start();
}
}
启动一个新线程,在新的线程运行 run 方法中的代码。
start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException。
新线程启动后会调用的方法。
如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为。
获取线程名。
修改线程名
获取线程状态
线程是否存活(还没有运行完毕)
这些方法已过时,容易破坏同步代码块,造成线程死锁,不推荐使用。
停止线程运行
挂起(暂停)线程运行
恢复线程运行
我将 Bootstrap 与 css 和 java 脚本结合使用。在不影响前端代码的情况下,我真的很难在css中绘制这个背景。在许多问题中,人们将宽度和高度设置为 0%。但是由于我的导航栏,我不能使用
我正在用 c 编写一个程序来读取文件的内容。代码如下: #include void main() { char line[90]; while(scanf("%79[^\
我想使用 javascript 获取矩阵数组的所有对 Angular 线。假设输入输出如下: input = [ [1,2,3], [4,5,6], [7,8,9], ] output =
可以用pdfmake绘制lines,circles和other shapes吗?如果是,是否有documentation或样本?我想用jsPDF替换pdfmake。 最佳答案 是的,有可能。 pdfm
我有一个小svg小部件,其目的是显示角度列表(参见图片)。 现在,角度是线元素,仅具有笔触,没有填充。但是现在我想使用一种“内部填充”颜色和一种“笔触/边框”颜色。我猜想line元素不能解决这个问题,
我正在为带有三角对象的 3D 场景编写一个非常基本的光线转换器,一切都工作正常,直到我决定尝试从场景原点 (0/0/0) 以外的点转换光线。 但是,当我将光线原点更改为 (0/1/0) 时,相交测试突
这个问题已经有答案了: Why do people write "#!/usr/bin/env python" on the first line of a Python script? (22 个回
如何使用大约 50 个星号 * 并使用 for 循环绘制一条水平线?当我尝试这样做时,结果是垂直(而不是水平)列出 50 个星号。 public void drawAstline() { f
这是一个让球以对角线方式下降的 UI,但球保持静止;线程似乎无法正常工作。你能告诉我如何让球移动吗? 请下载一个球并更改目录,以便程序可以找到您的球的分配位置。没有必要下载足球场,但如果您愿意,也可以
我在我的一个项目中使用 Jmeter 和 Ant,当我们生成报告时,它会在报告中显示 URL、#Samples、失败、成功率、平均时间、最短时间、最长时间。 我也想在报告中包含 90% 的时间线。 现
我有一个不寻常的问题,希望有人能帮助我。我想用 Canvas (android) 画一条 Swing 或波浪线,但我不知道该怎么做。它将成为蝌蚪的尾部,所以理想情况下我希望它的形状更像三角形,一端更大
这个问题已经有答案了: Checking Collision of Shapes with JavaFX (1 个回答) 已关闭 8 年前。 我正在使用 JavaFx 8 库。 我的任务很简单:我想检
如何按编号的百分比拆分文件。行数? 假设我想将我的文件分成 3 个部分(60%/20%/20% 部分),我可以手动执行此操作,-_-: $ wc -l brown.txt 57339 brown.tx
我正在努力实现这样的目标: 但这就是我设法做到的。 你能帮我实现预期的结果吗? 更新: 如果我删除 bootstrap.css 依赖项,问题就会消失。我怎样才能让它与 Bootstrap 一起工作?
我目前正在构建一个网站,但遇到了 transform: scale 的问题。我有一个按钮,当用户将鼠标悬停在它上面时,会发生两件事: 背景以对 Angular 线“扫过” 按钮标签颜色改变 按钮稍微变
我需要使用直线和仿射变换绘制大量数据点的图形(缩放图形以适合 View )。 目前,我正在使用 NSBezierPath,但我认为它效率很低(因为点在绘制之前被复制到贝塞尔路径)。通过将我的数据切割成
我正在使用基于 SVM 分类的 HOG 特征检测器。我可以成功提取车牌,但提取的车牌除了车牌号外还有一些不必要的像素/线。我的图像处理流程如下: 在灰度图像上应用 HOG 检测器 裁剪检测到的区域 调
我有以下图片: 我想填充它的轮廓(即我想在这张图片中填充线条)。 我尝试了形态学闭合,但使用大小为 3x3 的矩形内核和 10 迭代并没有填满整个边界。我还尝试了一个 21x21 内核和 1 迭代,但
我必须找到一种算法,可以找到两组数组之间的交集总数,而其中一个数组已排序。 举个例子,我们有这两个数组,我们向相应的数字画直线。 这两个数组为我们提供了总共 7 个交集。 有什么样的算法可以帮助我解决
简单地说 - 我想使用透视投影从近裁剪平面绘制一条射线/线到远裁剪平面。我有我认为是使用各种 OpenGL/图形编程指南中描述的方法通过单击鼠标生成的正确标准化的世界坐标。 我遇到的问题是我的光线似乎
我是一名优秀的程序员,十分优秀!