在之前的笔记中记录了线程与进程的区别,以及线程的启动方式,接下来就是关于线程的一些控制方法。
最主要的的中断线程的方法有两个:
Thread.sleep(long ms);//线程休眠
Thread.yield();//放弃CPU使用权
sleep()的参数是休眠的时长,为毫秒数,方法执行后,该线程会休眠该时长,当休眠结束后,该线程会重新参与竞争CPU的使用权,但是不是一休眠结束就可以抢占到CPU,所以实际上,该线程的实际不工作时长会大于设定的休眠时长。
yield()是该线程主动让出CPU的使用权,但是在让出之后同样会参与竞争,因此即使某线程调用了yield()方法,也可能继续占用CPU。
还可以设置某一个线程的优先级:
getPriority()//获取线程的优先级
setPriority()//设置线程的优先级
在这里要说明一下,设置大的优先级只能增大线程竞争到CPU的概率,但并不是绝对,每个线程都能抢占到CPU,因为线程的最大特点就是不确定性
第二个内容就是关于同步代码块。当多个线程公用同一个线程体时,容易出现数据丢失的情况。此时就需要用到同步锁来保护代码。
我们看一下下面的代码:
public class MyThread implements Runnable {
int i = 100;
@Override
public void run() {
while(true){
//获取当前正在执行的线程的名字
System.out.println(Thread.currentThread().getName()+"---"+ i);
i--;
Thread.yield();
if(i<0){
break;
}
}
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);
Thread t2 = new Thread(myThread);
t1.setName("线程a");
t2.setName("线程b");
t1.start();
t2.start();
}
}
当Test.java运行时,会出现下面的运行结果:
线程a---100
线程b---100
线程a---99
线程b---98
线程a---97
线程a---95
线程b---96
线程a---94
线程b---92
……
可以看到数据出现了丢失。我们可以使用同步锁来避免这样的情况出现:
同步锁要使用关键字synchronized
下面我们将MyThread线程体中的代码用该关键字包裹
public class MyThread implements Runnable {
int i = 100;
@Override
public void run() {
while(true){
//synchronized后面加上this,代表锁住的是一个MyThread对象
synchronized(this){
//获取当前正在执行的线程的名字
System.out.println(Thread.currentThread().getName()+"---"+ i);
i--;
Thread.yield();
if(i<0){
break;
}
}
}
}
}
再来看看运行结果:
线程a---100
线程a---99
线程a---98
线程a---97
线程b---96
线程b---95
线程b---94
线程b---93
线程b---92
线程b---91
线程b---90
线程b---89
线程b---88
线程b---87
线程b---86
线程b---85
线程b---84
线程b---83
线程b---82
这时数据就不会丢失。
在这里需要强调的是,synchronized关键字锁住的不是花括号内的代码,而是MyThread的对象,在synchronized内代码没有结束时,同步锁不会释放,这时,即使其他线程抢占到CPU,因为它没有这把同步锁,所以不能执行该部分代码,只能等到同步锁释放后才能竞争。