什么是多线程
线程和进程一样,线程是比进程更小的单位,所谓多线程就是进程里面执行更多更小的程序单元,这个程序单元就叫做线程,进程里的线程可以存在多个,同时进行
怎么创建线程
两种,一种是继承Thread类,一种是实现Runnable接口
继承和实现的区别
java程序的特点是单继承多实现,用继承有局限性,开发建议用实现的方法创建线程
为什么要重写run方法
该类用于存储线程要运行的代码,该存储功能就是run方法,类似于java程序里面的主线程main方法
d.start()和d.run()的区别
前者是开启线程并执行线程的run方法,后者仅仅是调用方法,而线程创建了并没有运行
线程的状态
被创建
运行(start())
临时状态(阻塞)-具备运行资格但没有执行权
冻结-(sleep(time))(wait())放弃执行资格(sleep时间到或notify返回运行状态)
消亡(stop)
多线程的安全问题
当多条语句再操作一个共享数据时,一个线程只执行了一部分,还没有执行完,另一个线程就参与进来,导致共享数据错误
解决办法:同步代码块/同步函数
同步代码块
class MyThread3 extends Thread{
int tick=100;
Object obj=new Object();
public void run(){
while(true){
synchronized (obj) {
if(tick>0){
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
}
}
}
}
同步函数:注意要把需要同步的函数提取出来再synchronized ,不然会把其他线程挡住,打印的结果只有一个线程在执行
class MyThread extends Thread{
int tick=100;
public void run(){
while(true){
show();
}
}
public synchronized void show(){
if(tick>0){
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
}
}
死锁
同步也会导致死锁的出现
原因是同步会占用一个锁,当另一个线程也需要这个锁的时候就会导致死锁的情况
public class test{
public test() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new Thread(new T1(o1, o2));
Thread t2 = new Thread(new T2(o1, o2));
t1.start();
t2.start();
}
}
class T1 implements Runnable {
Object o1;
Object o2;
T1(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
int tick=100;
synchronized (o1) {
if(tick>0){
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
synchronized (o2) {
}
}
}
}
class T2 implements Runnable {
Object o1;
Object o2;
T2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
int tick=100;
synchronized (o2) {
if(tick>0){
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
synchronized (o1) {
}
}
}
}
打印结果是
Thread-1…100
Thread-0…100
等待唤醒机制
wait()把线程放进线程池
notify()/notifyAll()线程池唤醒线程
都使用在同步中,因为要对持有锁的线程操作等待和唤醒必须是同一个锁
为什么等待唤醒定义在object中?
因为锁可以是任意对象,所以可以被任意对象调用的方法定义在object中
停止线程
1.stop()方法–已过时
2.停止线程,就是让run方法结束,开启多线程运行,运行代码通常是循环结构,只要控制住循环结构,就可以让run方法结束
3.interrput-当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结状态进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束
守护线程
setDaemon()
又叫后台运行线程,当所有前台线程结束后,后台线程自动结束
定义在线程启动之前
join
t1.join()
当前线程调用另一个线程的join方法,当前线程会进入阻塞状态,直到join方法执行完毕
join可以用来临时加入线程执行
优先级
就是抢资源的频率
一共10级,默认5
一般有三级,最高-10,最低-1,默认-5,可以通过setPriority设置
t1.setPriority(Thread.MAX_PRIORITY);
yield
暂停当前正在执行线程对象,执行其他的线程