Java多线程
进程:系统进行资源分配和调度的一个独立单位
线程:在进程中独立运行的子任务
使用多线程:多线程是异步的
线程启动顺序与start()执行顺序无关
非线程安全:指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。
解决方法:在run方法前加入synchronized关键字,使多个线程在执行run方法时,以排队的方式进行处理
public class MyThread extends Thread{
private int count = 5;
@Override
synchronized public void run(){
super.run();
count--;
System.out.println("由"+this.currentThread().getName()+" 计算,count="+count);
}
}
停止线程
在Java中有三种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
- 使用stop方法强行终止线程(不推荐),因为stop和suspend及resume一样,都是作为过期的方法,使用它们可能产生不可预料的结果
- 使用interrupt方法中断线程
判断线程是否是停止状态,Thread类中有以下两个方法:
- this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志置为清除状态(false)的功能
- this.isInterrupted():测试线程是否已经中断,不清除状态标志
暂停线程
suspend()方法暂停线程,resume()方法恢复线程的执行
缺点:
- 独占,使用suspend和resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象
- 不同步,容易出现因为线程的暂停而导致数据不同步的情况
yield方法
yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间,但放弃的时间不确定,有可能刚刚放弃,马上又获取CPU时间片
线程的优先级
- CPU优先执行优先级较高的线程对象中的任务,设置线程优先级使用setPriority()方法,值为1~10
- 线程优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A线程是一样的
- 优先级具有一定的规则性,也就是CPU尽量将执行资源让给优先级比较高的线程
- 优先级具有随机性
守护线程
在Java线程中有两种线程,一种是用户线程,另一种是守护线程
守护线程是一种特殊的线程,它的特性有”陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程
对象及变量的并发访问
synchronized同步方法
- 方法内的变量为线程安全(方法内变量为私有变量)
- 多个对象多个锁
- 可重入锁,自己可以再次获取自己的内部锁
- 出现异常,锁自动释放
- 同步不具有继承性
synchronized同步语句块
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程必须等待比较长的时间
synchronized同步代码块的使用:当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
即为在synchronized块中就是同步执行,不在synchronized块中就是异步执行,这样可以提高运行效率
在使用synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的”对象监视器”是一个
同步synchronized(this)代码块是锁定当前对象的
除了使用synchronized(this)格式来同步代码块外,Java还支持对”任意对象”作为”对象监视器”来实现同步功能,这个”任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象x)
- 1)在多个线程持有”对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象x)同步代码块中的代码——当多个线程同时执行synchronized(x){}同步代码块时呈同步效果
- 2)当持有”对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象x)同步代码块中的代码——当其他线程执行x对象中synchronized同步方法时呈同步效果
- 3)锁非this对象具有一定的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率,但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,则可以大大提高运行效率——当其他线程执行x对象方法里面的synchronized(this)代码块时也呈现同步效果
静态同步synchronized方法与synchronized(class)代码块
关键字synchronized还可以应用在static静态方法上,相当于对当前*.java文件对应的Class类进行持锁,Class锁可以对类的所有对象实例起作用
同步synchronized(class)代码块的作用和synchronized static方法的作用一样
多线程的死锁
死锁:不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成
当多个线程同时持有锁对象时,如果持有的是相同的锁对象,这些线程之间就是同步的,否则就是异步的
volatile关键字
主要作用是使变量在多个线程间可见,关键字volatile强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值
public class RunThread extends Thread {
volatile private boolean isRunning = true;
public boolean isRunning(){
return isRunning;
}
public void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
@Override
public void run(){
System.out.println("进入run了");
while(isRunning == true){
}
System.out.println("线程被停止了!");
}
}
public class Run {
public static void main(String[] args){
try{
RunThread thread = new RunThread();
thread.start();
Thread.sleep(1000);
thread.setRunning(false);
System.out.println("已经赋值为false");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
volatile具有非原子的特性,可能导致线程不安全,可以用synchronized关键字实现同步或使用AtomicInteger原子类进行实现
private AtomicInteger count = new AtomicInteger(0);
...
count.incrementAndGet();//自增1
synchronized代码块有volatile同步的功能
关键字synchronized可以使多个线程访问同一个资源具有同步性,而且它还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能