线程启动(start())
上文中已将提到了线程的几种创建方法,当线程创建后调用start()方法就可以启动线程了.
//线程类继承Runnable接口
static class MyThread implements Runnable{
@Override
public void run() {
System.out.println("线程启动了!");
}
}
//线程启动
public static void startThread(){
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
public static void main(String[] args) {
startThread();
}
线程名称的设置和获取
线程名字在创建的时候设置,获取是通过getName()方法获取
//线程名称设置和获取
public static void getAndSetThreadName(){
MyThread myThread = new MyThread();
//线程名字在创建的时候命名
Thread thread = new Thread(myThread,"线程1");
thread.start();
//通过getName()方法获取线程名字
System.out.println("线程名字:"+thread.getName());
}
public static void main(String[] args) {
//startThread();
getAndSetThreadName();
}
线程休眠(sleep())
sleep(millis)方法会让线程休眠一段时间
static class MyThread implements Runnable{
@Override
public void run() {
try {
//System.out.println("线程启动了!");
System.out.println("begin time = " + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("end time = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//线程启动
public static void startThread(){
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
public static void main(String[] args) {
startThread();
}
运行结果如图,线程暂停了两秒继续执行.
线程停止
在JAVA中线程停止有3种方法:
1. 使用退出标志使线程正常退出.
public class ThreadFlag extends Thread
{
public volatile boolean exit = false;
public void run()
{
while (!exit);
}
public static void main(String[] args) throws Exception
{
ThreadFlag thread = new ThreadFlag();
thread.start();
sleep(5000); // 主线程延迟5秒
thread.exit = true; // 终止线程thread
thread.join();
System.out.println("线程退出!");
}
}
2. 使用stop()方法强行终止线程,但这个方法不推荐使用,可能发生不可预料的结果.
3. 使用interrupt()方法中单线程.
这里着重讲interrupt()方法
为了更好地理解interrupt中断的原理先举一个例子:
static class MyThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("i = " + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(2);
thread.interrupt();
System.out.println("********************************");
}
上面代码的运行结果如图
在i=56后输出了**********,意味着主线程休眠的2ms里for语句执行了57次,然而在调用thread.interrupt()函数后for循环依旧没有停止,说明interrupt并没有让线程停止,只是给线程加了一个中断标志.那究竟怎样让线程停止呢?
在学习如何停止线程之前我们需要先了解两个判断线程是否为停止状态的函数
- public static boolean interrupted() : 测试currentThread()是否已经中断.
先来理解一下interrupted()函数的细节:
static class MyThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("i = " + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(1000);
thread.interrupt();
//Thread.currentThread().interrupt();
System.out.println("线程中断标志1 :" + Thread.interrupted());
System.out.println("线程中断标志2 :" + Thread.interrupted());
}
这是第一次运行的结果,然后去掉上面注释行Thread.currentThread().interrupt();
这证明了interrupted()方法:测试当前线程是否已经中断.这个当前线程是main,在第一次运行过程中main没有被中断因此输出始终未false,第二次运行加了中断main线程的代码后,输出为true,但为什么第二次输出线程的标志时为false呢? 查询interrupted()方法在官方的文档中解释:
测试当前线程是否已经中断.线程的中断状态由该方法清除.由此可知第二次输出false是因为第一次调用该方法的时候中断状态被清除了,所以输出false.
- public boolean this.isInterrupt() : 测试this关键字所在类对象是否已经中断.
接着是isInterrupted() 从方法声明中就可以看出它不是static()方法,作用于调用这个方法的对象.
static class MyThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("i = " + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(2);
thread.interrupt();
System.out.println("线程中断标志1 :" + thread.isInterrupted());
System.out.println("线程中断标志2 :" + thread.isInterrupted());
}
从运行结果来看,isInterrupted()并不会清除状态标志,输出两个true.
综上所述,这两个方法区别如下:
- this.interrupted() : 测试当前线程是否已经是中断状态,执行后具有清除状态标志,置为false的功能.
- this.isInterrupted() :测试线程Thread对象是否已经是中断状态,不清除状态标志.
说了这么多那到底怎样才能停止一个线程呢?稍安勿躁,想要真正了解一个知识,你要从头到尾的去研究,才能更好的掌握,而不是浅显的明白.废话不多说接下来就是停止线程的具体操作:
我们在了解了上面两个方法之后,就可以通过判断线程的中断状态来对线程进行停止.直接上代码:
static class MyThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 50000; i++) {
if (Thread.interrupted()){
System.out.println("线程是停止状态!退出循环");
break;
}
System.out.println("i = " + i);
}
System.out.println("for 后面的语句");
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(1);
thread.interrupt();
System.out.println("线程中断标志1 :" + thread.isInterrupted());
System.out.println("线程中断标志2 :" + thread.isInterrupted());
}
由此就可以实现线程的中断了,但是我们发现一个问题,interrupt()函数只是添加了一个状态,通过判断状态退出循环,但是for循环后面的语句还是会执行,此时还不是真正意义上的线程停止.接下来就要借助异常了!
interrupt() + 异常 实现线程停止
static class MyThread1 implements Runnable{
@Override
public void run() {
try {
for (int i = 0; i < 50000; i++) {
if (Thread.interrupted()){
System.out.println("线程是停止状态!");
throw new InterruptedException();
}
System.out.println("i = " + i);
}
System.out.println("for 后面的语句");
} catch (InterruptedException e) {
System.out.println("进入catch,线程停止!");
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(1);
thread.interrupt();
}
值得一提的是 在线程interrupt()之后调用sleep(),线程就会抛出异常而停止
static class MyThread1 implements Runnable{
@Override
public void run() {
try {
System.out.println("线程开始!休眠两秒");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
Thread.sleep(1000);
System.out.println("线程中断");
thread.interrupt();
}
运行结果:
程序是先让线程休眠然后在休眠过程中打上中断标志,可以看出抛出了异常,那么先打上中断标志再让线程休眠呢?上代码!
static class MyThread1 implements Runnable{
@Override
public void run() {
try {
System.out.println("线程开始!休眠两秒");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
System.out.println("线程中断");
thread.interrupt();
}
运行结果:
由此可以看出 只要interrupt()遇到sleep()就会抛出异常.
线程让步(yield())
yield()方法的作用是放弃当前CPU资源,让其他任务去占用CPU执行时间,放弃的时间是不确定的,有可能刚刚放弃就又获得了CPU时间片.
static class MyThread1 implements Runnable{
@Override
public void run() {
long beginTime = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < 5000000; i++) {
//Thread.yield();
count += i;
}
long endTime = System.currentTimeMillis();
System.out.println("任务用时:" + (endTime - beginTime)+"毫秒");
}
}
public static void main(String[] args) throws InterruptedException {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
}
第一次运行,没有线程让步,被注释掉了:
运算很快
第二次把注释去掉,每次for循环都加上线程让步:
很明显,CPu资源让给其他资源,速度变得很慢.
线程的优先级(setPriority())
在操作系统中,线程是可以设置优先级的,优先级越高的线程获得的CPU资源就越多,也就是让优先级更高的线程获得更多的时间片。
设置优先级的方法setPriority()。
先看一下setPriority()方法的源码:
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);
}
}
在JAVA中,线程的优先级分为1~10个等级,如果数值小于1或者大于10就会抛出异常IllegalArgumentException()。
优先级有几个特性:
- 优先级具有规律性,优先级大的在测试数值较大比如进行循环的时候,优先级大就先执行完,呈现规律性。
- 优先级具有随机性,比如优先级设置为5和6的两个线程运行结果也有可能是优先级为5的先执行完
上面总结一下就是:
优先级高的往往先执行完,但这个结果不是绝对的。
优先级对运行时间的影响:
static class MyThread implements Runnable{
private int count = 0;
public int getCount(){
return count;
}
@Override
public void run() {
while (true){
count++;
}
}
}
static class MyThread1 implements Runnable{
private int count = 0;
public int getCount(){
return count;
}
@Override
public void run() {
while (true){
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.setPriority(1);
thread.start();
MyThread1 myThread1 = new MyThread1();
Thread thread1 = new Thread(myThread1);
thread1.setPriority(10);
thread1.start();
Thread.sleep(2000);
System.out.println("thread = " + myThread.getCount());
System.out.println("thread = " + myThread1.getCount());
}
可见优先级高的运行速度就越快,几乎每次运行后thread1的值都比thread大,就是因为thread1优先级更高,获取了更多的时间片。