线程API:
常用构造器:
Thread(Runnable r)
创建一个指定任务的线程对象
Thread(Runnable r, String name)
创建一个指定任务,指定名称的线程对象
Thread(String name)
创建一个指定名称的线程对象
常用方法:
String getName();获取线程名称
long getId();获取线程ID
int getPriority();获取优先级
boolean isAlive();线程是否活动状态
boolean isDaemon();线程是否为守护(后台)线程
Thread.State getState();获取线程状态
boolean isInterrupted():是否被打断
void interrupt():打断阻塞状态下的线程对象
static void yield():线程对象让步的功能(让出时间片段,回到就绪状态)
线程调度:
- 即优先级
-
1-10,10为最高,1最低,5默认
Thread.MIN_PRIORITY–最小优先级
Thread.MAX_PRIORITY–最高优先级
Thread.NORM_PRIORITY–默认优先级对应的方法:
void setPriority(int priority)
用于设置线程调度(优先级)
守护线程:
- 线程分两类
-
一类是普通线程(前台线程),一类是守护线程(后台线程)
当线程只剩下守护线程时,所有线程都结束(死亡)。
void setDaemon(boolean on)
true将此线程标记为守护线程,false将此线程标记为普通线程(不调用方法,默认为false)
/**
* 守护线程的学习:
*
* 模拟rose和jack两个人跳水
* rose:喊10次跳水,然后噗通一声,结束
* jack:你跳我就跳,rose跳水后,结束
*/
public class DeamonDemo {
public static void main(String[] args) {
Thread rose = new Thread(){
public void run(){
for(int i=0;i<10;i++){
try {
Thread.sleep(500);
System.out.println("我要跳了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("------噗通------");
}
};
Thread jack = new Thread(){
public void run(){
while(true){
try {
Thread.sleep(500);
System.out.println("你跳我就跳");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
/*将jack设置成守护线程,注:需要在启动之前设置才有效*/
jack.setDaemon(true);
rose.setPriority(Thread.MAX_PRIORITY);
jack.setPriority(Thread.MIN_PRIORITY);
rose.start();
jack.start();
}
}
测试结果:
其他堵塞的两个方法
- static sleep(long time)
- 用于使当前线程进入阻塞状态,时间为time毫秒,time毫秒后,会进入就绪状态,若期间被打断,会出现异常InterruptedException
- void join()
- 将当前线程(调用方法的线程对象)插入到某一个线程中,使某一个线程进入阻塞状态,当前线程执行完(死亡)后,另一个线程进入就绪状态
同步锁:
/**
* 模拟2个人捡豆子
* 桌上有20可豆子
* 每人1秒拿走一颗豆子
*/
public class Bean implements Runnable{
static int num = 20;
public void run(){
while(num>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余豆子"+ --num);
}
}
public static void main(String[] args) {
Runnable r = new Bean();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
当多个线程操作临界资源时,可能会出现线程安全隐患问题
临界资源可能是:
(1)静态资源
(2)实例变量
想解决该问题,需要使用同步操作
- 异步操作
- 多线程的并发操作,相当于各干各的
- 同步操作
- 相当于一个做完,另一个再做
-
线程在内部提供了一个内置的锁机制保证原子性,用于线程进行同步操作
锁:需要注意两点
(1)锁是一个对象
(2)若想同步操作,多个线程操作的必须是同一个锁对象
synchronized(锁对象的引用){
需要同步的代码块
}
- 锁机制
- 当一个线程执行到同步代码块后,会得到锁对象的使用权,其他线程若执行到此处,会发现锁对象被占用,处于等待,线程执行完同步代码块后,或者出现异常,都会自动释放锁对象。
- 合适的锁对象
- 必须是一个引用类型,而且必须使多个线程都可以使用这个锁对象,因此this对象比较适合
同步块的范围
(1)可以是方法内的一部分方法,可以是全部代码(相当于给方法上了锁)
/**
* 模拟2个人捡豆子
* 桌上有20可豆子
* 每人1秒拿走一颗豆子
*/
public class Bean implements Runnable{
static int num = 20;
public void run(){
while(num>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(this){
if(num>0){
System.out.println("剩余豆子"+ --num);
}
}
}
}
public static void main(String[] args) {
Runnable r = new Bean();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
多运行几次,结果都是相同的
(2)给成员方法上添加修饰词synchronized,锁对象为this
如果一个类的所有成员方法都是用了synchronized时,当某个线程操作了一个方法,另外的线程即使操作的不是这个方法,也会进入锁池状态
/**
* 模拟计算器运算
* 分别计算加法减法结果
*/
public class Computer{
private int a;
private int b;
public Computer(int a, int b) {
this.a = a;
this.b = b;
}
/**加法运算*/
public synchronized void add(){
System.out.println("开始计算加法");
int sum = a+b;
System.out.println("得出加法结束");
System.out.println("加法结果为"+sum);
}
/**减法运算*/
public synchronized void sub(){
System.out.println("开始计算减法");
int sub = a-b;
System.out.println("得出减法结果");
System.out.println("减法结果为"+sub);
}
public static void main(String[] args) {
Computer c = new Computer(4,2);
Thread t1 = new My1(c);
Thread t2 = new My2(c);
t1.start();
t2.start();
}
}
/**线程1:计算加法*/
class My1 extends Thread{
private Computer com;
public My1(Computer com) {
this.com = com;
}
public void run(){
com.add();
}
}
/**线程2:计算减法*/
class My2 extends Thread{
private Computer com;
public My2(Computer com) {
this.com = com;
}
public void run(){
com.sub();
}
}
(3)静态方法上也可以添加synchronized,锁对象为类对象,调用方式:类名.class,每个类都有一个唯一的类对象
等待阻塞
注:只能在同步锁中使用
- wait():
- 当前获取锁对象的线程准备释放锁,给其他线程获取锁的机会
- wait(long time):
- 当前获取锁对象的线程(没有被通知)在延迟time毫秒后自动释放锁对象
- wait(long time,int naons):
- 比上一个方法延迟时间更加精确(在毫秒(10^-3s)后,添加一个纳秒(10^-9s))
- notify()/notifyAll():
-
当前获取锁对象的线程准备释放锁,使用此方法通知处于wait方法等待的线程,让等待的线程开始准备竞争锁对象,当前调用的线程仍在运行状态
notify():只会随机通知等待线程中的其中一个
notifyAll():通知所有等待线程