线程状态:
创建状态---》就绪状态----》运行状态-----》阻塞状态----》死亡状态
线程调度:线程调度指按照特定机制为多个线程分配Cpu的使用权
方法:
void setPriorrity (int newPriority) 更改线程的优先级
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "线程A");
Thread t2 = new Thread(mr, "线程B");
//输出两个线程的优先级
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
//更改线程优先级
t1.setPriority(t1.MAX_PRIORITY);
t2.setPriority(t2.MIN_PRIORITY);
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
//线程优先级高只能说明线程获取的cpu资源的该路大一些,不能保证每一次优先级高的线程先获取cpu资源
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
//线程延迟
Thread.sleep(5000);`//休眠5秒
viod join() 等待该线程终止
//线程强制执行:t1强制执行,一直等到t1执行完毕之后,才会释放Cpu资源给其他线程执行,在调用join()方法之前,多个线程依然是抢占cpu
t1.join();
//millis:一毫秒为单位的等待时长
//nanos:要等待的附加纳秒时长
//需要处理InterruptedException异常
static void yield() 暂停当前执行的线程对象,并执行其他线程
//线程礼让:让当前执行run()方法的线程释放Cpu资源,给其他线程一个获得CPU资源的一个机会,但是当前线程还会抢占Cpu资源,也就是说,当前线程释放CPU,就看其他线程能不能抓住这个机会
Thread.yield();
//暂停当前线程,允许其他具有相同优先级的线程获得运行机会
//该线程处于就绪状态,不转为阻塞状态
//只是一种可能,但是不能保证一定会实现礼让
void interrupt() 中断线程
boolean isAive() 测试线程是否处于活动状态
多线程共享数据引发的问题
多个线程操作同一共享数据资源时,将引发数据不安全问题
在一个线程中操作共享数据的时候,还没有操作完毕,线程失去了CPU资源,CPU资源被另外一个线程获取,另外一个线程会接着上一个线程操作数据继续执行操作,
当另一个线程操作数据完毕之后,第一个线程又获取了CPU资源,此时,第一个线程看到的数据时第二个线程操作后的数据,由此就会引发数据不安全问题
同步方法:
使用synchronized修饰的方法控制对类成员的变量的访问
访问修饰符 synchronized 返回类型方法名(参数列表){}或者synchronized 访问修饰符 返回类型 方法名(参数列表){}
//定义属性表示票库里的票数
private int count = 10;
//定义属性表示用户买到的是第几张票
private int num = 0;
@Override
public void run() {
while(true){
if(!sale()){
break;
}
}
}
public synchronized boolean sale(){
// 如果票的数量小于,就不再买票
if (count<=0) {
return false;
}
//每卖出一张票,总数-1,卖出去的票数+1
count--;
num++;
//模拟网络延迟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//输出
System.out.println(Thread.currentThread().getName()+"买到了"+num+"张票,还剩"+count+"票");
return true;
}
将线程要操作的代码放入同步方法中,当线程执行到同步方法的时候,一定会执行完同步方法里所有代码后在释放cpu资源,从而一个线程对数据的操作不会受其他线程的影响
同步代码块
使用synchronized关键字修饰的代码块:synchronized(syncObject){//需要同步的代码块}
syncObject为同步的对象,通常this
public void run() {
while(true){
//同步代码块
synchronized (this){
// 如果票的数量小于,就不再买票
if (count<=0) {
break;
}
//每卖出一张票,总数-1,卖出去的票数+1
count--;
num++;
//模拟网络延迟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//输出
System.out.println(Thread.currentThread().getName()+"买到了"+num+"张票,还剩"+count+"票");
}
}
}
多个并发线程访问同一资源的同步代码块时
同一时刻只能有一个线程进入synchronized(this)同步代码块
当一个线程访问一个synchroized(this)同步代码块时,其他synchroized(this同步代码块同样的被锁定
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以分为该资源的非synchronized(this)同步代码
线程安全的类型
ArrayList类的add()方法为非同步方法,当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题
方法是否同步 | 效率 | 适用场景 | |
线程安全 | 是 | 低 | 多线程并发共享资源 |
非线程安全 | 否 | 高 | 单线程 |
常见的类型比较
Hashtable&&HashMap
Hashtable:继承关系实现了Map接口,Hashtable继承Dictionary类,线程安全,效率较低键和值都不允许为null
HashMap:继承关系实现了Map接口,继承AbstractMap类,非线程安全,效率较高键和值都允许为null
StringBuffer&&StringBuilder
前者线程安全,后者非线程安全