多线程: 一个程序同时运行多个任务,每个任务称为一个线程。线程之间共享数据。
实现多线程的几种方式
- 继承Thread类(单继承,不易扩展,并且线程之间数据不共享)
public class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
}
}
- 继承Runnable接口(没有返回值)
public class MyRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
}
}
- 继承Callable接口(有返回值)
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return ThreadLocalRandom.current().nextInt(1000);
}
}
创建线程并开启线程
启动多线程的唯一方法是Thread.start()方法,这个方法将创建一个执行run()方法的新线程,不能直接调用run()方法,直接调用run()方法,不会新建线程,只是调用了一个普通的方法。
- 继承Thread类
public static void main(String[] args) {
MyThread myThread = new MyThread(); //创建
myThread.start(); //开启
}
- 继承Runnable接口
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); //task
//thread1 和 thread2 共享数据
Thread thread1 = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable);
thread .start(); //开启
}
- 继承Callable接口
public static void main(String[] args) throws InterruptedException, ExecutionException {
//FutureTask将Callable转为Future和Runnable,Future封装返回的结果
MyCallable myCallable = new MyCallable();
FutureTask<Integer> task = new FutureTask<>(myCallable);
Thread thread = new Thread(task); //Runnable
thread.start(); //开启
Integer result = task.get(); //Future,获取返回值
System.out.println(result);
}
同步
目的:线程之间共享数据,为了保证数据的一致性
- 锁对象和条件对象
public class Test{
private Lock lock = new ReentrantLock(); //锁对象,每个Test对象都有一个锁对象,显式锁
private Condition condition = lock.newCondition(); //条件对象
private Integer count;
public void method() {
lock .lock(); //获取锁,可能发生阻塞
//lock.tryLock() //尝试获取锁,获取成功返回true
//lock.tryLock(100,TimeUnit.SECONDS) //有时长的获取锁,等待期间被中断抛出InterruptedException
try {
while (count<0) //满足某一条件才能执行
//condition.await(100,TimeUtil.SECONDS); //时间到了自己唤醒,拥有再次进行条件判断的机会
condition.await(); //将线程加入这一条件的等待集,线程放弃cpu执行权并释放锁,等待其他线程调用condition.signal()或者condition.signalAll()被唤醒
//do something
} finally {
lock .unlock(); //释放锁
}
}
}
/**
* 每个对象有一个内部锁,该锁有一个内部条件
* 调用Object.wait()将线程加入内部条件的等待集,线程放弃cpu执行权并释放锁
* Object.notify(),Object.notifyAll将线程唤醒
*/
public synchronized void method1() {
}
/**
* synchronized 修饰静态方法,该类的Class对象被锁定
*/
public static synchronized void method2() {
}
public void method() {
synchronized (this) { //获取this对象的内部锁,也可以是其他对象
}
}
Thread常用方法
方法 | 解释 |
---|---|
public static Thread currentThread() | 获取当前线程 |
public void start() | 启动多线程 |
public static void sleep(long millis) | 带时长的休眠,释放cpu执行权,不释放锁 |
public final void join() | 等待调用该方法的线程终止 |
public void interrupt() | 中断线程,将中断标记设置为true ,线程被阻塞调用这个方法,中断标志被清除,设置为false ,并且产生InterruptedException |
public static boolean interrupted() | 静态方法,判断当前线程是否被中断,调用这个方法中断状态被清除,变为false |
public boolean isInterrupted() | 实例方法,判断线程是否被中断,线程被阻塞无法判断中断状态,会产生InterruptedException |
public static void yield() | 线程让步,放弃cpu执行权(这个方法我感觉并没有什么用) |
线程的状态(6种)
- NEW 新建,使用
new Thread(...)
创建线程 - RUNNABLE 可运行,调用线程的
start()
方法后,包含正在运行的线程【正在执行run()
方法】 - BLOCKED 被阻塞,线程等待获取某个锁的过程
- WAITING 等待,调用
Object.wait()
,Thread.join()
,Thread.sleep()
,Lock.tryLock()
,Condition.await()
线程进入等待状态,从等待状态恢复后拥有再一次进行条件判断的机会,条件满足继续执行。 - TIMED WAITING 计时等待,顾名思义,等待的方法传入等待的时长,时间到了,自动唤醒
- TERMINATED 被终止,正常结束的线程,或者没运行到最后就return,或者发生异常的线程,或者调用
Thread.stop()
,Thread.stop()
已过时,不建议使用,易造成线程死锁