线程中的常用方法:
setName():设置线程名字
getName():返回线程名字
run():调用线程中的run方法。注意:run方法仅仅是一个普通的方法,并不会启动新线程
setPriority():更改线程的优先级
getPriority():获得线程的优先级
sleep():在指定的毫秒数内让该线程休眠(暂停执行)
interrupt():中断线程。注意:并不是真正的结束线程,一般是结束正在休眠的线程。
线程的其他方法:
yield():线程的礼让
这是Thread类中的静态方法
表示让出CPU,让其他线程先执行,但礼让的时间不确定。因此线程的礼让不一定成功
礼让是否成功是由CPU资源决定的。如果资源十分充足,两个线程同时执行没什么问题,则不会礼让成功。
join():线程的插队
调用join方法,一旦插队成功,则先执行插入的线程的所有任务,后执行其他线程。
用户线程:也叫工作线程,当线程的任务执行完成或通知结束
守护线程:一般是为工作线程服务的。当所有的工作线程结束,守护线程自动结束。
常见的守护线程:垃圾回收机制
// 而我们希望main线程结束时,A线程也结束:只需将A线程设置为守护线程
MyDaemonThread thread = new MyDaemonThread();
// 将线程设置为守护线程,后启动线程
thread.setDaemon(true);
thread.start();
线程同步机制:在多线程编程中,一些敏感的数据不允许被多个线程同步访问,此时需要使用线程同步技术。
即:保证数据在同一时刻,最多有一个线程访问,以保证数据的完整性
线程同步:仅仅只有一个线程对内存进行操作,其他线程不能对内存进行操作,直到该线程完成操作,其他线程才可以对该内存地址进行操作。
同步的具体方法:Synchronized关键字
同步代码块:仅仅只有得到对象的锁,才可以对(同步)代码块进行操作
Synchronized (对象) {
// 同步代码块;
}
同步方法:
public Synchronized void m() {
// 方法体;
}
public static void main(String[] args) {
SellTicket sellTicket = new SellTicket();
// 同时开启多个线程进行售票
new Thread().start();
new Thread().start();
new Thread().start();
}
// 利用线程同步机制解决票数超卖问题
class SellTicket implements Runnable {
private int ticketCount = 100;
private boolean loop;
// 避免同时多个线程访问ticketCount,造成票的超卖,所以使用线程同步机制
public void sell() {
// 存在票进行卖票操作
if(ticketCount > 0) {
System.out.println(Thread.currentThread().getName() + "售票中....");
System.out.println("剩余票数" + (--ticketCount));
} else {
loop = false;
System.out.println("票卖完了....");
}
}
// 在run方法中完成业务逻辑
@Override
public void run() {
while (loop) {
sell();
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
分析同步原理:
1.线程(a、b、c)同时争夺资源
2.哪个线程(a线程)得到对象锁,就执行代码操作对象,操作完后,返回对象锁
3.多个线程(a、b、c)再次同时争夺对象锁
Java中存在对象争夺锁,来保证数据的完整性。
每个对象都对应着一个可称为“互斥锁”的标记,用来保证任一时刻仅有一个线程访问该对象
关键字synchronized与对象的互斥锁联系
使用关键字synchronized修饰时,表示任一时刻仅仅只有一个线程访问。
同步静态方法(static修饰),默认上锁的是当前类.class(同一时刻仅有一个线程访问这个类)
同步非静态方法(不用static修饰),默认上锁的是this对象(同一时刻仅有一个线程访问对象)
实现同步的步骤:
1.首先分析出需要上锁的代码(业务逻辑代码)
2.选择使用同步代码块还是同步方法(同步代码块效率更高)
3.注意:要求多线程的锁对象必须是同一个