最近在看书,想在这里介绍一下java多线程的一些知识,加深记忆,分享成果…
直奔主题…
线程优先级
目前操作系统采用时分
的形式来调度线程,操作系统会分出一个一个时间片,线程会分配到若干时间片,当线程用完这个时间片就会发生线程调度,等待下一次分配.线程被分配的时间片越多,此线程就获得资源越多,而线程优先级就决定了此线程被分配的时间片多少!
java线程中,通过成员变量priority控制优先级.优先级范围从1-10
,线程初始化时,通过setPriority来设置线程优先级(默认是5).下面代码示例:
/**
* 线程的优先级
* Created by gzd on 2017/1/10.
*/
public class Priority {
private static volatile boolean notStart = Boolean.TRUE;
private static volatile boolean notEnd = Boolean.TRUE;
public static void main(String[] args) throws InterruptedException {
ArrayList<Job> jobs = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int priority = i < 5 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY;
Job job = new Job(priority);
jobs.add(job);
Thread thread = new Thread(job, "线程: " + i);
thread.setPriority(priority);
thread.start();
}
notStart = Boolean.FALSE;
TimeUnit.SECONDS.sleep(10);
notEnd = Boolean.FALSE;
for (Job job : jobs){
System.out.println("job priority: "+job.priority + ",count :"+job.jobCount);
}
}
private static class Job implements Runnable {
private int priority;
private long jobCount;
public Job(int priority) {
this.priority = priority;
}
@Override
public void run() {
while (notStart) {
Thread.yield();
}
while (notEnd) {
Thread.yield();
jobCount++;
}
}
}
}
程序运行结果是:
job priority: 1,count :12786382
job priority: 1,count :12719559
job priority: 1,count :12784550
job priority: 1,count :12489459
job priority: 1,count :12499625
job priority: 10,count :13335791
job priority: 10,count :12952607
job priority: 10,count :13257944
job priority: 10,count :12994291
job priority: 10,count :13351521
可以看到,线程优先级,并没有起到绝对性的作用,这就说明,不能依靠线程的优先级来保证程序结果,因为操作系统不需要理会它.
线程的状态
java线程的生命周期一共有6种状态.分别为:
- NEW 初始状态,线程已经创建,但是还没有执行start方法
- RUNNABLE 运行状态,就绪和运行状态的统称
- BLOCKED 阻塞状态,阻塞于锁
- WAITING 等待状态
- TIME_WAITING 超时等待,区别于上一个状态,他可以在制定的时间自行返回
- TERMINATED 终止状态,线程执行结束
下面给出一段示例代码:
/**
* 线程状态
* Created by gzd on 2017/1/10.
*/
public class ThreadState {
//这个线程一直睡眠
private static Runnable timeWaiting = () -> {
while (true) {
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
}
}
};
//这个线程一直在当前类实例上等待
private static Runnable waiting = () -> {
while (true) {
synchronized (ThreadState.class) {
try {
ThreadState.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//这个演示block
private static Runnable block = () -> {
synchronized (Priority.class){
while (true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
public static void main(String[] args) {
new Thread(timeWaiting, "timeWaiting").start();
new Thread(waiting, "waiting").start();
new Thread(block,"block-1").start();
new Thread(block,"block-2").start();
}
}
利用jstack
工具来查看线程的状态:
D:\workspace\study>jps
7744 RemoteMavenServer
12936 AppMain
12428 Jps
12444 Launcher
D:\workspace\study>jstack 12936
"block-2" #15 prio=5 os_prio=0 tid=0x0000000019dc1000 nid=0x2cdc waiting on condition [0x000000001b38e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
"block-1" #14 prio=5 os_prio=0 tid=0x0000000019dbf000 nid=0x2d04 waiting for monitor entry [0x000000001b28e000]
java.lang.Thread.State: BLOCKED (on object monitor)
"waiting" #13 prio=5 os_prio=0 tid=0x0000000019dbe800 nid=0x3028 in Object.wait() [0x000000001b18f000]
java.lang.Thread.State: WAITING (on object monitor)
"timeWaiting" #12 prio=5 os_prio=0 tid=0x0000000019dbd800 nid=0x192c waiting on condition [0x000000001b08e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
为了节省篇幅,已经删除掉其他没用的打印结果,可以看到:
- waiting线程是在WAITING ,没有一个确切的时间.
- timeWaiting线程因为使用了sleep,所以,是TIMED_WAITING 状态,等待一个确切的时间后启动线程.
- block-2”因为获得了Priority.class的锁所以状态为TIMED_WAITING.
- block-1因为block-2正在占用锁,所以他没有获取到锁,所以它的状态为BLOCKED.
关于jstack的使用:可以在命令行内直接输入jstack,也可以去文件夹内双击启动(windows),具体可以谷歌一下
线程状态的变化可以用以下UML图来说明:
注意:java是讲运行和就绪合并成RUNNABLE状态,阻塞在synchronized的为阻塞状态,但是阻塞在java.concurrent包中Lock接口的状态却是扥带状态,因为其对于阻塞的实现使用的时LockSupport类的方法.
Daemon线程
Daemon线程为支持型线程,具体作用为程序中后台调度以及支持工作.其实可以理解为,如果目前只有Daemon线程,那么JVM可以停止工作退出.
可以通过Thread.setDaemon(true)讲线程设置为Daemon线程
设置方法:
/**
* Created by gzd on 2017/1/10.
* 怎么样设置Daemon线程
*/
public class Daemon {
private static Runnable daemonRunner = () -> {
try {
System.out.println("========begin============");
TimeUnit.SECONDS.sleep(5);
System.out.println("========end============");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("========finally============");
}
};
public static void main(String[] args) {
Thread daemonThread = new Thread(daemonRunner, "daemonThread");
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.start();
}
}
运行程序之后可以发现,没有任何打印结果,因为main方法中,启动了daemonThread线程之后就没有其他操作而终止.也没有其他需要执行的线程,所以JVM执行退出,finally块儿里面的也不会执行.当我们想要做一些主要程序以外的其他工作时,可以用此线程来完成.
这篇就先到这里,下一篇会继续介绍线程的启动/停止,线程间通讯,join等等!