Java多线程总结
概论
多线程是指多个任务同时执行,的目的是为了提高机器性能。实际上在单个cpu时,多线程只是看起来同时进行,在实际上某一时刻它只有一个程序在走。多核cpu同一时刻可以运行多个任务。多线程开发的目标是高可用,高性能,高并发。一个程序可以有多个进程,一个进程可以包含多个线程。
1、开启多线程
开启多线程有三个办法,Java多线程的几种创建方式。
1、继承Thread类重写run()方法,调用start()开启。
2、实现Runnable接口,重写run()方法,借用装饰类Thread调用start()方法:new Thread(new Runnable实现类()).start()。
3、实现Callabler接口,重写call方法,通过ExecutorService类创建服务,调用其submit方法开启线程,通过其shutdown方法关闭服务。
方法三中的call方法可以抛出异常,可以有返回值,方法一二中的run不可抛出异常,没有返回值。多用实现,少用继承(Java中只有接口可以多继承)。
Runnable方便共享资源(并发):
public class Test{ public static void main(String[] args) { Test01 ts = new Test01(); new Thread(ts,"线程1").start(); new Thread(ts,"线程2").start(); } } class Test01 implements Runnable{ //多个线程共享同一个资源 private int money=9; @Override public void run() { while (true) { if (money <= 0) { break; }else{ System.out.println(Thread.currentThread().getName()+"-->"+money--); } } } }
运行结果:
2、线程状态
如图所示:
1、进入就绪的方式:调用start()方法、接触阻塞、调用yield()方法、JVM内部控制
2、进入阻塞的方式:调用sleep()方法、调用wait()方法、调用join()方法、IO读写操作
3、不建议使用stop()或者destroy()方法结束线程,推荐让线程体自行执行结束,一般使用加入标识的方式控制线程,避免进入死循环。
使用getState()可以获取线程的状态:
public static enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
private State() {
}
}
3、Thread类常用方法
构造器:
new Thread(子类对象) 不设置Name,默认为thread-x ,x为线程个数。
new Thread(子类对象,线程Name) 设置线程Name
常用静态方法:
Thread.sleep(毫秒) 使得线程阻塞。常常用于模拟延迟。
Thread.currentThread() 获取此处在运行的线程对象。常常配合其它方法使用。
Thread.yield() 此线程主动释放cpu,进入就绪状态。
常用普通方法:
setName(名字) 设置线程名字。
getName() 获取线程名字。
isAlive() 返回线程是否活着。
jion() 插队,在其它线程中使用让其它线程阻塞,等它先执行完。
setDaemon(boolean b) 设置是否为守护线程。线程开启时默认为用户线程。只要所有的用户线程执行完毕,程序就结束。
setPriority(优先级) 设置优先级,1-10。提供常量:Thread.MAX_PRIORITY、Thread.MIN_PRIORITY、Thread.NORM_PRIORITY。
getPriority() 获取优先级。并不是优先级大的就一定先执行,它只是给虚拟机的建议。
getState() 获取线程状态。
4、并发控制
为了保证多个线程操作同一个对象时不产生数据错误,需要对并发进行控制。
4.1 synchronized 锁
我们可以使用 synchronized 同步方法或同步块对指定的对象的资源进行锁定,本线程锁了它,其它线程就得排队等本线程用完(释放锁)才能用这个对象。synchronized是可重入锁,Java可重入锁学习。
synchronized 方法:
在方法前面加上synchronized声明,此方法便为同步方法,它锁的是this对象。它锁不到其它类的对象(非this)。
synchronized void test() {
}
synchronized块:
可以锁任何对象。精准定位。
void test() {
synchronized(Object ob) {
}
}
4.2 volatile 声明变量
1、对volatile变量的写会立即刷新到主存
2、对volatile变量的读会读主存中的新值
4.3 死锁
简介:
过多的同步可能造成互相不释放资源,从而导致互相等待,一般发生与同步中持有多个对象的锁。
例如:
一个不可重入锁多次获取同一个对象的锁,就会产生死锁。
如何避免:
不在同一个代码块中,同时拥有多个对象的锁。
5、线程通信
线程之间可以进行协作,实现线程之间的通信借助java.lang.Object类中的方法:
final void wait(); //线程释放拥有的锁,进入等待 final void wait(long time); //线程进入等待,在指定毫秒数之后进入就绪状态 final void notifiy(); //唤醒一个处于等待状态的线程 final void notifyAll(); //唤醒同一个对象上所有调用wait()方法的线程
注意:这些方法只能使用在同步代码块中。例子:Java消费者生产者模式,并发控制。