暂停线程执行
(1)final void join():调用该方法的线程强制执行,导致调用它的线程进入阻塞状态,而不会导致其它的线程阻塞。该线程执行完毕后,调用该线程的线程再继续执行。
(2)static void sleep(long millis):使当前正在执行的线程休眠millis毫秒,线程处于阻塞状态。
(3)static void yeild():当前正在执行的线程暂停一次,允许其他线程执行,不阻塞,只是回到就绪状态。如果没有其他等待执行的线程,则当前线程就会马上恢复执行。
线程的优先级
设置和获取当前线程优先级的方法
(1)final getPriority():获取线程的优先级
(2)filnal void setPriority(int priority):设置线程的优先级(并不是优先级越高就一定能先执行),优先级只能是1-10之间的整数
public class Test {
public static void main(String[] args) {
System.out.println("最高优先级:"+Thread.MAX_PRIORITY);
System.out.println("最低优先级:"+Thread.MIN_PRIORITY);
System.out.println("默认优先级:"+Thread.NORM_PRIORITY);
//主线程的优先级
Thread t=Thread.currentThread();
System.out.println("获取主线程的优先级:"+t.getPriority());
Thread t2=new Thread(new MyThread());
System.out.println("新建的线程优先级为:"+t2.getPriority());
/**
* 优先级超高越有可能先被调用执行,但是不一定
*
*/
t2.setPriority(6);
System.out.println("t2线程的优先级:"+t2.getPriority());
// t2.setPriority(100); 非法参数,因为优先级只能是1-10之间的整数
}
}
class MyThread implements Runnable{
@Override
public void run() {
}
}
多线程安全性
假设一个这样的场景:一共还有5张车票,有三个窗口可以售最后这五张票,每个窗口有十人排队,5张票卖完了则结束。根据此场景用代码来表示如下:
public class TestTicket {
public static void main(String[] args) {
TicketThread th = new TicketThread();
Thread t1 = new Thread(th,"窗口A");
Thread t2 = new Thread(th,"窗口B");
Thread t3 = new Thread(th,"窗口C");
t1.start();
t2.start();
t3.start();
}
}
class TicketThread implements Runnable{
private int ticket = 5;//5张车票
@Override
public void run() {
for (int i=0;i<10;i++){
if(ticket>0){
Thread t = Thread.currentThread();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"在售第"+(ticket--)+"票");
}
}
}
}
出现的结果如下(由于多线程,cpu调度执行不唯一,所以运行结果不唯一)
我们发现出现了窗口A第0张票和窗口B销售第-1张票的错误。原因是当还有最后一张票时,即ticket=1时,线程t1进入判断条件(ticket>0),条件满足,然后让出资源,没有继续执行程序;此时线程t2得到资源,程序执行到判断条件(ticket>0),条件满足,然后让出资源,没有继续执行程序;此时线程t3得到资源,程序执行到判断条件(ticket>0),条件满足,然后打印语句和(ticket–),此时ticket=0;然后t1线程得到资源继续执行程序,所以此时窗口A打印出来的是第0张票,以此类推,线程t2(窗口B)打印出来的是第-1张票。这就是线程不安全,为了线程安全,我们应该控制当一个窗口售票工作结束时,其他窗口才能进行售票,这就需要用到线程同步。
线程同步
方法一:同步代码块,synchronized(obj){ },obj称为同步监听器
public class TestTicket1 {
public static void main(String[] args) {
TicketThread1 th = new TicketThread1();
Thread t1 = new Thread(th,"窗口A");
Thread t2 = new Thread(th,"窗口B");
Thread t3 = new Thread(th,"窗口C");
t1.start();
t2.start();
t3.start();
}
}
class TicketThread1 implements Runnable{
private int ticket = 5;
@Override
public void run() {
for (int i=0;i<10;i++){
synchronized (this){
if(ticket>0){
Thread t = Thread.currentThread();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"在售第"+(ticket--)+"票");
}
}
}
}
}
方法二:同步方法,public synchronized … 方法名(参数列表){ }
public class TestTicket2 {
public static void main(String[] args) {
TicketThread2 th = new TicketThread2();
Thread t1 = new Thread(th,"窗口A");
Thread t2 = new Thread(th,"窗口B");
Thread t3 = new Thread(th,"窗口C");
t1.start();
t2.start();
t3.start();
}
}
class TicketThread2 implements Runnable{
private int ticket = 5;
@Override
public void run() {
//每个窗口排了10个人
for (int i=0;i<10;i++) {
//调用同步方法
this.saleTicket();
}
}
//同步方法,无需指定同步监视器,同步监视器只能是当前对象this
public synchronized void saleTicket(){
if(ticket>0){
Thread t = Thread.currentThread();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"在售第"+(ticket--)+"票");
}
}
}
用上了线程同步后,售票过程就正常了,线程同步原理是让一段代码连续执行完之后,其它线程才能有资格执行,即当执行同步代码时,其它线程进入阻塞。避免了线程间抢资源,导致出现不合理情况。