多线程
java程序中只少两个线程,分别是主线程和垃圾回收线程
线程的创建
方式一:
继承Thread类
- 子类覆盖父类中的run方法,将线程运行的代码存放在run中。
- 建立子类对象的同时线程也被创建。
- 通过调用start方法开启线程。
public static void main(String[] args) {
Test t1 = new Test("test1");
t1.start();
Test t2 = new Test("test2");
t2.start();
}
class Test extends Thread{
private String name;
public Test(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(name+":"+i);
}
}
}
用Thread的注意事项
- 同一个多次调用会报异常
线程的各种状态
- 创建状态
- 新建一个线程对象可采用Thread类的构造方法来实现,例如:Thread thread = new Thread();
- 就绪状态
- 调用该线程的start()方法就可以启动线程,当线程启动时,线程进入就绪状态
- 运行状态
- 当就绪状态的线程被调用并获得处理器资源时,线程进入运行状态
- 堵塞状态
- 在特殊情况下,如人为挂起,让将让出CPU并暂时中止自己的执行,进入堵塞状态
- 死亡状态
- 线程调用stop()方法时,或run()方法执行结束后,
- 处于死亡状态的线程不具备继续运行的能力
方式二:
实现Runnable接口
-
子类覆盖接口中的run方法
-
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
-
Thread类对象调用start方法开启线程。
Thread和Runnable的关系
- Thread是Runnable的子类
- Thread和Runnable的区别
- Runnable可以共享数据
线程操作的常用方法
- 取得和设置线程名字getName()
- main函数也是一个线程,一个java程序的的运行至少要启动两个线程
- 判断线程是否启动isAlive()
- 主线程有可能比其他的线程先执行完
- isAlive() 判断线程是否处于活动状态
- sleep(long millis) 线程休眠
- join() 强制执行线程
- interrupt() 中断线程的某种状态
- setDaemon将线程设置成后台线程
线程安全问题
出现安全问题的原因:
-
多个线程访问出现延迟
-
线程随机性 。
(一般出现在在多个线程有数据共享,并且run中的语句不止只有一句)
同步(synchronized)
同步代码块格式:
synchronized(对象){
需要同步的代码
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
同步的特点:
同步的前提:
- 同步需要两个或者两个以上的线程
- 多个线程使用的是同一个锁。
未满足这两个条件,不能称其为同步
同步的弊端:
当线程相当多时,因为每个线程都会去判断 同步上的锁,这是很耗费资源的,无形 中会降低程序的运行效率
同步函数:
格式:在函数上加上synchronized修饰符即可
同步函数的锁是this
而同步代码块的锁可以是任意对象
死锁
同步应用过多就有可能会出现死锁,所同步不要使用过分太多
停止线程
- 定义循环结束标记
- 因为线程运行代码一般都是循环,只要控制了循环即可。
- 使用interrupt(中断)方法。
- 该方法是结束线程的冻结状态,使线程回到 运行状态中来