多线程
让程序同时做多件事情
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
应用场景:拷贝迁移大文件,加载大量的资源文件
并发和并行
并发:同一时刻,多个指令在单个CPU上交替执行
并行:同一时刻,多个指令在多个CPU上同时执行
实现方式
1.继承Thread类的方式进行实现
继承然后实现run方法,然后创建Thread对象,调用start方法
2.实现Runnable接口的方式进行实现
实现接口,重写run方法,创建自己类的对象,然后创建Thread对象把自己的对象传进去,调用start方法
3利用Callable接口和Future接口方式实现
实现接口,重写call方法有返回值,创建对象,创建FutureTask对象传进去,然后创建Thread对象将FutureTask对象传进去,然后调用start方法,用get方法来获取返回值
常见的成员方法
String getName()返回此线程的名称
默认名字是Thread-X,X是下个线程号,自增
void setName(String name)设置线程的名字(构造方法也可以设置名字)
static Thread currentThread()获取当前线程的对象
static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority) 设置线程的优先级
final int getPriority() 获取线程的优先级
final void setDaemon(boolean-on)设置为守护线程
非守护线程先执行,执行完,守护线程就不用执行了(听着没有什么意义,但是举个例子就懂了比如说QQ聊天的时候,同时接收一个文件,聊天结束接收文件自然不会再继续,那么接收文件就是守护线程)
public static void yield()出让线程/礼让线程
public static void join()插入线程/插队线程
举例t.join(),t表示上面的那个线程,插入当前线程,当前线程就是下面的线程
线程的生命周期
首相创建线程对象,然后start()启动,这个时候它是有执行资格但是没有执行权,它就绪不停的抢CPU,当它抢到之后就拥有了执行权就开始运行代码,这个时候会出现三种情况。第一是直接run()代码执行完之后,线程死亡,变成垃圾;第二种被其他线程抢走CPU执行权,继续就绪抢夺CPU执行权;第三种是sleep()或者其他阻塞方法导致它没有执行资格也没有执行权,这个时候就是阻塞等待解放,阻塞结束回到就绪状态。
线程的安全问题
多个线程操作同一个数据,会出现相同数据操作,超出范围等问题
究其根本是因为,线程执行有随机性,所以会同时操作,如果我们可以将操作共享数据的代码锁起来,一个一个操作就可以解决这个问题。
同步代码块
synchronized(锁){操作共享数据的代码},锁对象唯一加static
同步方法
就是把synchronized关键字加到方法上
修饰符 synchronized 返回值类型 方法名(方法参数){...}锁住了方法里面所有代码,不能自己指定锁对象
Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法void lock():获得锁手动上锁、手动释放锁
void unlock():释放锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
ReentrantLock():创建一个ReentrantLock的实例
死锁
互斥条件、请求与保持条件、不剥夺条件、循环等待条件。